ZOJ 3631 Watashi's BG(超大背包问题)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 3631 Watashi's BG(超大背包问题)相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3631
题意:集训队集训N天,每天都要花钱吃饭,第i天花费vi的钱(可以报销或自己花钱),一共能报销M元,问最多能报销多少。
题解:一看就是一个01背包问题,但是题目给定的每天花费vi取值过大,数组不能存下,所以这里要用到折半搜索。
每天就只有取和不取两种状态,可以用二进制表示,先枚举前N/2天,然后枚举后面的N-N/2天,同时二分找最大值,
这里借鉴了一个dalao用set集合存状态的操作。
1 #include <set> 2 #include <cstdio> 3 #include <algorithm> 4 using namespace std; 5 6 struct node{ 7 int x; 8 node (int _x):x(_x){} 9 bool operator<(const node &x1)const 10 { 11 return this->x > x1.x; 12 } 13 }; 14 15 int num[44]; 16 set <node> T; 17 18 int main(){ 19 int n,m; 20 while(scanf("%d %d",&n,&m)!=EOF){ 21 int ans=-1; 22 int n2=n/2; 23 T.clear(); 24 for(int i=0;i<n;i++) scanf("%d",&num[i]); 25 for(int i=0;i< 1<< n2;i++){ 26 int sw=0; 27 for(int j=0;j<n2;j++){ 28 if(i>>j&&1) sw+=num[j]; 29 } 30 T.insert(node(sw)); 31 } 32 for(int i=0;i< 1<<(n-n2);i++){ 33 int sw=0; 34 for(int j=0;j<(n-n2);j++){ 35 if(i>>j&&1) sw+=num[n2+j]; 36 } 37 if(sw<=m) ans=max(T.lower_bound(node(m-sw))->x+sw,ans); 38 } 39 printf("%d\n",ans); 40 } 41 return 0; 42 }
还有一种用dfs+剪枝的操作,很是精妙,学习了。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int N=44; 6 int a[N],b[N]; 7 int n,m,ans; 8 9 void dfs(int step,int cnt){ 10 if(cnt>m) return ; 11 ans=max(ans,cnt); 12 if(step<1) return ; 13 //精妙剪枝,当前的报销+还没有处理的账单小于等于最大值,这个肯定不能超过最大值 14 //所以继续处理下去也没有意义,直接剪枝 15 if(cnt+b[step]<=ans) return ; 16 dfs(step-1,cnt); 17 dfs(step-1,cnt+a[step]); 18 } 19 20 int main(){ 21 while(scanf("%d %d",&n,&m)!=EOF){ 22 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 23 b[0]=0; 24 for(int i=1;i<=n;i++) b[i]=b[i-1]+a[i]; 25 ans=0; 26 dfs(n,0); 27 printf("%d\n",ans); 28 } 29 return 0; 30 }
以上是关于ZOJ 3631 Watashi's BG(超大背包问题)的主要内容,如果未能解决你的问题,请参考以下文章
ZOJ 4019 Schrödinger's Knapsack
ZOJ 3696 Alien's Organ(泊松定理,期望值)