码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ 3631 Watashi's BG(超大背包问题)

时间:2017-10-02 16:44:22      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:超过   this   problem   ons   get   操作   blog   div   i++   

题目链接: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(超大背包问题)

标签:超过   this   problem   ons   get   操作   blog   div   i++   

原文地址:http://www.cnblogs.com/Leonard-/p/7620288.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!