链接:
题意:
给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小,如果有一样的,取个数最小的
思路:
子集个数共有2^n个,所以不能全部枚举,但是可以分为两部分枚举;枚举一半的所有情况,然后后一半二分即可;
代码:
1 #include"bits/stdc++.h" 2 #define N 45 3 using namespace std; 4 typedef long long LL; 5 6 int n; 7 LL a[N]; 8 9 LL Abs(LL x)10 {11 return x<0?-x:x;12 }13 14 int main()15 {16 while(scanf("%d", &n), n)17 {18 for(int i=0; iM;22 map ::iterator it;23 pair ans(Abs(a[0]), 1);24 25 for(int i=1; i<1<<(n/2); i++)26 {27 LL sum = 0;int cnt = 0;28 for(int j=0; j<(n/2); j++)29 {30 if((i>>j)&1)31 {32 sum += a[j];33 cnt ++;34 }35 }36 ans = min(ans, make_pair(Abs(sum), cnt));///全部是前半部分的;37 if(M[sum])///更新cnt为小的;38 M[sum] = min(M[sum], cnt);39 else40 M[sum] = cnt;41 }42 43 for(int i=1; i<1<<(n-n/2); i++)44 {45 LL sum = 0;int cnt = 0;46 for(int j=0; j<(n-n/2); j++)47 {48 if((i>>j)&1)49 {50 sum += a[j+n/2];51 cnt ++;52 }53 }54 ans = min(ans, make_pair(Abs(sum), cnt));///全部是后半部分的;55 56 it = M.lower_bound(-sum);///找到第一个大于-sum的位置,然后取两种情况的最小值;57 58 if(it != M.end())59 ans = min(ans, make_pair(Abs(sum+it->first), cnt+it->second));60 if(it != M.begin())61 {62 it--;63 ans = min(ans, make_pair(Abs(sum+it->first), cnt+it->second));64 }65 }66 printf("%I64d %d\n", ans.first, ans.second);67 }68 return 0;69 }