POJ 3977 折半枚举

链接:

http://poj.org/problem?id=3977

题意:

给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小

如果有一样的,取个数最小的 

题解:

np难题,但是因为数据小,所以可以通过折半枚举求解

先枚举前一半的所有情况 用map记录下来,

然后在枚举后一半的所有情况,再在前一半记录的map里面找相加的和 与0最接近的

开始我用的set,但是set不好处理重复的

不过map居然也可以用lower_bound!

另外poj好像不支持long long的abs 所以要自己写一个

代码:

 1 #include <map>
 2 #include <set>
 3 #include <cmath>
 4 #include <queue>
 5 #include <stack>
 6 #include <cstdio>
 7 #include <string>
 8 #include <vector>
 9 #include <cstdlib>
10 #include <cstring>
11 #include <sstream>
12 #include <iostream>
13 #include <algorithm>
14 #include <functional>
15 using namespace std;
16 #define rep(i,a,n) for (int i=a;i<n;i++)
17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
18 #define pb push_back
19 #define mp make_pair
20 #define all(x) (x).begin(),(x).end()
21 #define SZ(x) ((int)(x).size())
22 typedef vector<int> VI;
23 typedef long long ll;
24 typedef pair<int, int> PII;
25 const ll MOD = 1e9 + 7;
26 const int INF = 0x3f3f3f3f;
27 const double EPS = 1e-10;
28 const double PI = acos(-1.0);
29 const int MAXN = 8010;
30 // head
31 
32 ll list[40];
33 map <ll, int> mm;
34 typedef pair<ll, int> pli;
35 
36 ll labs(ll x) {
37     return x >= 0 ? x : -x;
38 }
39 
40 int main() {
41     int n;
42     while (cin >> n, n) {
43         mm.clear();
44         rep(i, 0, n) scanf("%lld", list + i);
45         pli ans = mp(1e18, 0);
46         int n1 = n / 2, n2 = n - n1;
47         rep(i, 1, 1 << n1) {
48             ll sum = 0;
49             int num = 0;
50             rep(j, 0, n1) if (i&(1 << j)) sum += list[j], num++;
51             if (!mm[sum] || mm[sum] > num) mm[sum] = num;
52             pli t = mp(labs(sum), num);
53             if (t < ans) ans = t;
54         }
55         rep(i, 1, 1 << n2) {
56             ll sum = 0;
57             int num = 0;
58             rep(j, 0, n2) if (i&(1 << j)) sum += list[n1 + j], num++;
59             pli t = mp(labs(sum), num);
60             if (t < ans) ans = t;
61             map<ll, int>::iterator k = mm.lower_bound(-sum);
62             if (k != mm.end()) {
63                 t = mp(labs((*k).first + sum), num + (*k).second);
64                 if (t < ans) ans = t;
65             }
66             if (k != mm.begin()) --k;
67             if (k != mm.end()) {
68                 t = mp(labs((*k).first + sum), num + (*k).second);
69                 if (t < ans) ans = t;
70             }
71         }
72         cout << ans.first << ' ' << ans.second << endl;
73     }
74     return 0;
75 }

 

posted @ 2017-04-11 13:00  Flowersea  阅读(615)  评论(0编辑  收藏  举报