TOJ 4095 BoatBurglary 分治

http://acm.tju.edu.cn/toj/showp4095.html

题意:

N个物品,N <= 30,每个有重量w[i],w[i] <= 10^9,现在重量少了D,问可能少了几个物品,判断是否多解和无解,唯一解输出少掉的物品数量。

分析:

如果重量没那么大就是一个简单的背包,这个数据范围用背包做状态根本存不下。然后脑抽了一直在搜索,一直Tle一直Tle。。其实后面搜索策略已经优化的不错了,只搜一半的层数,然后搜出来的集合的sum以及补集的sum分别判断是否等于D。但是这还是逃不过C(15, 30)的状态数。

请教了学长得到一个分治算法。。折半处理,枚举选和不选,分别是2^15,然后排序,对于一侧的一个值,找另一侧是否有一个值使他们俩相加等于D就可以了。复杂度是o(2^(n/2)lg(2^(n/2)))

然后我wa了好几次,一方面是自己写萎了,一方面不知道题目有没有trick。一个是D的范围,不开longlong可能读入就会爆,一个是w[i]和D貌似有可能为0,然后该怎么处理为0的情况我也晕了。。反正底下程序是AC的。。

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 
  6 struct arr{
  7     int num;
  8     long long sum;
  9 } a[100000], b[100000];
 10 int T, n, sizea, sizeb;
 11 long long D, w[40];
 12 bool legal[40];
 13 bool cmp(arr a, arr b)
 14 {
 15     return a.sum < b.sum;
 16 }
 17 int main()
 18 {
 19     scanf("%d", &T);
 20     int cas = 0;
 21     while(T--)
 22     {
 23         scanf("%d %lld", &n, &D);
 24         for (int i = 0; i < n; i++) scanf("%lld", w+i);
 25         sizea = sizeb = 1;
 26         a[0].num = b[0].num = a[0].sum = b[0].sum = 0;
 27         for (int i = 0; i <= n/2; i++){
 28             int tmp = sizea;
 29             for (int j = 0; j < tmp; j++){
 30                 a[sizea].num = a[j].num + 1;
 31                 a[sizea++].sum = a[j].sum + w[i];
 32             }
 33         } 
 34         for (int i = n/2+1; i < n; i++){
 35             int tmp = sizeb;
 36             for (int j = 0; j < tmp; j++){
 37                 b[sizeb].num = b[j].num + 1;
 38                 b[sizeb++].sum = b[j].sum + w[i];
 39             }
 40         }
 41         sort(a, a+sizea, cmp);
 42         sort(b, b+sizeb, cmp);
 43         int count = 0, ans;
 44         memset(legal, 0, sizeof(legal));
 45         for (int i = 0; i < sizea; i++){
 46             if (a[i].sum > D || count > 1) break;
 47             if (a[i].sum == D){
 48                 int number = a[i].num;
 49                 if (!legal[number]){
 50                     legal[number] = true;
 51                     count ++;
 52                     ans = number;
 53                 }
 54             }
 55             if (a[i].sum <= D){
 56                 long long need = D - a[i].sum;
 57                 int l = 0, r = sizeb-1, pos = -1;
 58                 while (l <= r)
 59                 {
 60                     int mid = (l + r) >> 1;
 61                     if (b[mid].sum == need){
 62                         pos = mid;
 63                         break;
 64                     }
 65                     else if (b[mid].sum < need) l = mid + 1;
 66                     else r = mid - 1;
 67                 }
 68                 if (pos != -1){
 69                     int tmp = pos;
 70                     while(pos < sizeb && b[pos].sum == b[tmp].sum){
 71                         int number = a[i].num + b[pos].num;
 72                         if (!legal[number]){
 73                             legal[number] = true;
 74                             count ++;
 75                             ans = number;
 76                         }
 77                         pos ++;
 78                     }
 79                     pos = tmp-1;
 80                     while(pos >= 0 && b[pos].sum == b[tmp].sum){
 81                         int number = a[i].num + b[pos].num;
 82                         if (!legal[number]){
 83                             legal[number] = true;
 84                             count ++;
 85                             ans = number;
 86                         }
 87                         pos --;
 88                     }
 89 
 90                 }
 91             }
 92         }
 93         cas ++;
 94         printf("Case #%d: ", cas);
 95         if (count == 0) printf("IMPOSSIBLE\n");
 96         else if (count > 1) printf("AMBIGIOUS\n");
 97         else printf("%d\n", ans);
 98     }
 99     return 0;
100 }

 

posted @ 2014-08-13 14:37  james47  阅读(184)  评论(0编辑  收藏  举报