1208 - 부분집합의 합 2

문제 링크


 

https://www.acmicpc.net/problem/1208

 

 

문제 요약


 

크기 인 집합이 주어진다. 이 때 부분집합의 합이 가 되는 경우의 수를 구하는 문제다.

 

 

문제 풀이

 

 

 

 


 

이 최대 40이기 때문에 완전탐색으로는 안된다. 따라서 다른 방법이 필요하다. 이런 경우에는 왼쪽 절반과 오른쪽 절반의 모든 경우의 수를 각각 구하고 이분탐색을 통해 이 경우의 수를 합쳐나갈 수 있다.

 

크기 인 집합을 왼쪽부터 개의 완전탐색 경우의 나머지 오른쪽의 완전탐색 경우를 다 구해 놓는다. 이 때 왼쪽의 경우의 수와 오른쪽 경우의 수를 어떻게 합쳐야 할까? 왼쪽의 경우 중 가능한 한가지 합이 라고 가정을 해 보자. 그렇다면 오른쪽 경우의 수에서 찾아야 할 합은 가 될 것이다. 따라서 왼쪽의 경우의 수에 대해서 가능한 오른쪽의 모든 경우의 수를 찾아 답에 누적해 나가면 된다.

 

이 40일 때 시간복잡도는 이므로 시간내에 들어올 수 있다.

 

 

소스 코드

 

 

 

 


 

코드 보기

 

#include <stdio.h> #include <vector> #include <algorithm>  using namespace std;  int N, S, A[41];  void func(int pos, int end, int sum, vector<int>& vi) {   if (pos == end) {     vi.push_back(sum);     return;   }   func(pos + 1, end, sum, vi);   func(pos + 1, end, sum + A[pos], vi); }  int main() {   scanf("%d%d", &N, &S);   for (int i = 0 ; i < N ; ++i) {     scanf("%d", &A[i]);   }   vector<int> L, R;   func(0, N / 2, 0, L);   func(N / 2, N, 0, R);      sort(R.begin(), R.end());   long long ans = 0;   for (int val : L) {     int target = S - val;     auto hi = upper_bound(R.begin(), R.end(), target);     auto lo = lower_bound(R.begin(), R.end(), target);     ans += hi - lo;   }      if (S == 0) {     --ans;   }   printf("%lld\n", ans); }

 

 

'알고리즘 > 문제풀이' 카테고리의 다른 글

11670 - 초등 수학  (0) 2016.11.16
13344 - Chess Tournament  (0) 2016.11.15
1867 - 돌멩이 제거  (1) 2016.11.14
2843 - 마블  (1) 2016.11.14
1704 - 붕어빵타이쿤  (1) 2016.11.12

Designed by JB FACTORY