超大背包问题

   

超大背包问题

  • Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others)
  • Total Submission(s): 17     Accepted Submission(s): 5
Description

有重量和价值分别为 wi ( 1 ≤ wi ≤ 1015 )、vi ( 1 ≤ vi ≤ 1015 ) 的 n (1 ≤ n ≤ 40 )个物品。从这些物品中挑选总重量不超过 C (1 ≤ C ≤ 1015)的物品,求所选挑选方案中价值总和的最大值。

Input

多测试用例。每个测试用例:

第一行是 n 和 C,接下来有 n 行,每行两个正整数,分别是各个物品的 wi 和 vi

Output

每个测试用例输出一行:最大价值。

Sample Input

4 5
2 3
1 2
3 4
2 2

Sample Output

7

 
二分搜索,加一个贪心。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=42;
 5 const ll inf=0x3f3f3f3f;
 6 
 7 int n;
 8 ll w[maxn],v[maxn];
 9 ll W;
10 
11 pair<ll,ll> ps[1<<(maxn/2)];
12 
13 int main()
14 {
15     ios::sync_with_stdio(0); std::cin.tie(0);
16     while( cin >> n >> W){
17         for(int i=0;i<n;i++)
18             cin >> w[i] >> v[i];
19 
20         int N=n>>1; ///因为每个物品只有选与不选的操作,所以有两种选择,根据组合原理为2^n。
21         ///但是2^n太大,可以分成两分进行搜索
22         for(int i=0;i<(1<<N);i++){
23             ll sumw=0,sumv=0;
24             for(int j=0;j<N;j++){
25                 if(i>>j&1){  ///先进行i>>j,即看选还是不选
26                     sumw+=w[j];
27                     sumv+=v[j];
28                 }
29             }
30             ps[i]=make_pair(sumw,sumv);
31         }
32 //        for(int i=1;i<(1<<n2);i++){
33 //            cout << ps[i].first << "  " << ps[i].second << endl;
34 //        }
35         sort(ps,ps+(1<<N)); ///对重量进行排序
36 //        for(int i=1;i<(1<<n2);i++){
37 //            cout << ps[i].first << "  " << ps[i].second << endl;
38 //        }
39         int m=1;
40         for(int i=1;i<(1<<N);i++){
41             if(ps[m-1].second < ps[i].second) ///若重量比前面元素大,价值却比前面小,就放弃。有贪心
42               ps[m++]=ps[i];
43         }
44 
45         ll ans=0;
46         for(int i=0;i< 1<<(n-N);i++){
47             ll sumw=0,sumv=0;
48             for(int j=0;j<n-N;j++){ ///同上原理
49                 if(i>>j&1){
50                     sumw+=w[N+j];
51                     sumv+=v[N+j];
52                 }
53             }
54             if(sumw<=W){
55                 ll tv=(lower_bound(ps,ps+m,make_pair(W-sumw,inf))-1)->second;
56                 ///进行二分,找W-sumw后最大的价值,所以用lower_bound;
57                 ans=max(ans,sumv+tv);
58             }
59         }
60         cout << ans << endl;
61     }
62     return 0;
63 }

 

posted @ 2018-05-13 22:59  flyer_duck  阅读(153)  评论(0编辑  收藏  举报