超大背包问题
超大背包问题
- 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 }