CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

1514: Packs

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 61  Solved: 4
[Submit][Status][Web Board]

Description

Give you n packs, each of it has a value v and a weight w. Now you should find some packs, and the total of these value is max, total of these weight is equal to m.

Input

First line is a number T( T ≤ 5) represent the test cases.
Then for each set of cases, first line is n (1 ≤ n ≤ 40) and m (1 ≤ m < 2^31), follow n line each is Wi (1 ≤ Wi < 2^31) and Vi (-2^31 < Vi < 2^31).

Output

Each case a line for max value.(Each set of inputs to ensure the solvability)

Sample Input

2
3 3
1 1
2 2
3 4
5 2
1 -5
1 -8
1 0
1 -2
1 5

Sample Output

4
5

注意:这里要求是满足总重量必须固定,而不是接近总重量。这就成了直接折半枚举,map大法就行了。


 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <string>
 6 #include <vector>
 7 #include <set>
 8 #include <map>
 9 #include <stack>
10 #include <queue>
11 #include <sstream>
12 #include <iomanip>
13 using namespace std;
14 typedef long long LL;
15 const long long INF=99999999999999999LL;
16 const int EXP=1e-5;
17 const int MS=42;
18 
19 map<LL,LL> mp;
20 int n;
21 LL W;
22 
23 LL w[MS],v[MS];
24 
25 void solve()
26 {
27     mp.clear();
28     int n1=n/2;
29     for(int i=0;i<(1<<n1);i++)
30     {
31         LL sw=0,sv=0;
32         for(int j=0;j<n1;j++)
33         {
34             if((i>>j)&1)
35             {
36                 sw+=w[j];
37                 sv+=v[j];
38             }
39         }
40         mp[sw]=max(mp[sw],sv);
41     }
42     LL ans=-INF;
43     for(int i=0;i< 1<<(n-n1);i++)
44     {
45         LL sw=0,sv=0;
46         for(int j=0;j<(n-n1);j++)
47         {
48             if((i>>j)&1)
49             {
50                 sw+=w[n1+j];
51                 sv+=v[n1+j];
52             }
53         }
54        if(mp.count(W-sw))
55             ans=max(ans,mp[W-sw]+sv);
56     }
57     printf("%lld
",ans);
58 }
59 
60 
61 int main()
62 {
63     int T;
64     scanf("%d",&T);
65     while(T--)
66     {
67         scanf("%d%lld",&n,&W);
68         for(int i=0;i<n;i++)
69             scanf("%lld%lld",&w[i],&v[i]);
70         solve();
71     }
72     return 0;
73 }
如果是重量不大于 W ,那么就要折半枚举+二分查找。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <string>
  7 #include <vector>
  8 #include <set>
  9 #include <map>
 10 #include <stack>
 11 #include <queue>
 12 #include <sstream>
 13 #include <iomanip>
 14 using namespace std;
 15 typedef long long LL;
 16 const int INF=0x4fffffff;
 17 const int EXP=1e-5;
 18 const int MS=40;
 19 
 20 int n;
 21 LL W;
 22 LL w[MS],v[MS];
 23 struct node
 24 {
 25     LL w,v;
 26     bool operator <(const node &a) const   //注意一定要加上const
 27     {
 28         return w<a.w||(w==a.w&&v<a.v);
 29     }
 30 }nodes[1<<(MS/2)];
 31 
 32 LL find(LL w,int cnt)
 33 {
 34     int l=0,r=cnt;
 35     while(r-l>1)         //  左闭右开区间处理起来更方便。
 36     {
 37         int mid=(l+r)/2;
 38         if(nodes[mid].w<=w)
 39             l=mid;
 40         else
 41             r=mid;
 42     }
 43     return nodes[l].v;
 44 }
 45 
 46 void solve()
 47 {
 48     int n1=n/2;
 49     int cnt=0;
 50     for(int i=0;i<(1<<n1);i++)
 51     {
 52         LL sw=0,sv=0;
 53         for(int j=0;j<n1;j++)
 54         {
 55             if((i>>j)&1)
 56             {
 57                 sw+=w[j];
 58                 sv+=v[j];
 59             }
 60         }
 61         nodes[cnt].w=sw;
 62         nodes[cnt++].v=sv;
 63     }
 64     sort(nodes,nodes+cnt);
 65     int last=0;
 66     for(int i=0;i<cnt;i++)
 67     {
 68         if(nodes[last].v<nodes[i].v)
 69         {
 70             nodes[++last]=nodes[i];
 71         }
 72     }
 73     cnt=last+1;
 74     LL ans=0;
 75     for(int i=0;i< 1<<(n-n1);i++)
 76     {
 77         LL sw=0,sv=0;
 78         for(int j=0;j<(n-n1);j++)
 79         {
 80             if((i>>j)&1)
 81             {
 82                 sw+=w[n1+j];
 83                 sv+=v[n1+j];
 84             }
 85         }
 86         if(sw<=W)
 87         {
 88             LL tv=find(W-sw,cnt);
 89             ans=max(ans,sv+tv);
 90         }
 91     }
 92     printf("%lld
",ans);
 93 }
 94 
 95 
 96 int main()
 97 {
 98     int T;
 99     scanf("%d",&T);
100     while(T--)
101     {
102         scanf("%d%lld",&n,&W);
103         for(int i=0;i<n;i++)
104             scanf("%lld%lld",&w[i],&v[i]);
105         solve();
106     }
107     return 0;
108 }
 
 
原文地址:https://www.cnblogs.com/767355675hutaishi/p/4388362.html