poj1276 Cash Machine

来源:互联网 发布:初中物理辅导软件 编辑:程序博客网 时间:2024/05/17 09:17

题意:

735 3  4 125  6 5  3 350633 4  500 30  6 100  1 5  0 1735 00 3  10 100  10 50  10 10
第一行的意思是给一个735大小的背包

然后3表示后面有3种物品,4和125表示,有个物体大小为125,价值为125,有4个

多重背包求解,交的时候忘了注释freopen,狂WA。。二进制解法如下。


#include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<list>using namespace std;vector<int>coins;void BinaryDistribute(int num,int val)//二进制分解,分解做法见背包九讲,将num个价值val的物体分解{int k;for(k=1;num-k*2+1>0;k=(k<<1)){coins.push_back(k*val);}coins.push_back(val*(num-k+1));}int d[101000];int main(){//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);int maxValue;while(cin>>maxValue){coins.clear();int n;cin>>n;while(n--){int num;int val;cin>>num>>val;BinaryDistribute(num,val);}n=coins.size();for(int i=0;i<=maxValue;i++){d[i]=0;}for(int i=0;i<n;i++)//01背包问题{for(int j=maxValue;j>=coins[i];j--){if(d[j]<d[j-coins[i]]+coins[i]){d[j]=d[j-coins[i]]+coins[i];}}}printf("%d\n",d[maxValue]);}//system("PAUSE");return 0;}

单调队列解法

虽说单调队列理论上比二进制快,但是我写的这个单调队列用了800多ms,可能是我第一次实现的原因→ →

关于单调队列优化多重背包的算法,网上大部分是含糊不清,推荐一篇我学习的文章

《国家集训队2009论文集浅谈几类背包题》


#include<iostream>#include<algorithm>#include<cstdio>#include<deque>using namespace std;int v[15];//int k[15];//表示物品v[i]的件数int d[101000];//d[i]表示体积为i的背包装得的最大值struct T{int index;int used;};int main(){int MAX_V;while(~scanf("%d",&MAX_V)){int n;scanf("%d",&n);for(int i=0;i<n;i++){scanf("%d %d",&k[i],&v[i]);}for(int i=0;i<=MAX_V;i++){d[i]=0;}for(int i=0;i<n;i++)//处理v[i]{for(int m=0;m<v[i];m++)//处理d[m],d[m+v[i]],d[m+2*v[i]],d[m+3*v[i]].........{deque<T>Q;//单调队列d[m+k*v[i]]-k*v[i]的递减队列,队列中实际存储的index是m+k*v[i]for(int j=m;j<=MAX_V;j+=v[i]){int tused=0;while(!Q.empty()&&d[Q.front().index]+v[i]*(k[i]-Q.front().used)<j){Q.pop_front();}if(!Q.empty()&&d[j]<d[Q.front().index]+(j/v[i]-Q.front().index/v[i])*v[i]){d[j]=d[Q.front().index]+(j/v[i]-Q.front().index/v[i])*v[i];tused=(j-Q.front().index)/v[i]+Q.front().used;}while(!Q.empty()&&d[Q.back().index]-Q.back().index/v[i]*v[i]<=d[j]-j/v[i]*v[i]){Q.pop_back();}T t;t.used=tused;t.index=j;Q.push_back(t);}}}int ant=0;for(int i=0;i<=MAX_V;i++){if(ant<d[i]){ant=d[i];}}printf("%d\n",ant);}return 0;}





更快的单调队列

以上那个单调队列,虽然不知道为什么那么慢,但是最近看了一些其他人写的单调队列解法,模仿了一下,速度是47ms

显然快了很多

解法就是虽然同样是单调队列,但是却没有一个真正的队列结构来维护

d[j]的前状态,显然是单调队列中的队首,但是由于计算状态的时候有d[m],d[m+v[i]],d[m+2*v[i]]

每个状态的最优前状态显然是前面的d[j-v[i]]

#include<iostream>#include<algorithm>#include<cstdio>#include<deque>using namespace std;int v[15];//int k[15];//表示物品v[i]的件数int d[101000];//d[i]表示体积为i的背包装得的最大值int num[101000];int main(){int MAX_V;while(~scanf("%d",&MAX_V)){int n;scanf("%d",&n);for(int i=0;i<n;i++){scanf("%d %d",&k[i],&v[i]);}for(int i=0;i<=MAX_V;i++){d[i]=0;}for(int i=0;i<n;i++)//处理v[i]{for(int j=0;j<=MAX_V;j++){num[j]=0;}for(int m=0;m<v[i];m++)//处理d[m],d[m+v[i]],d[m+2*v[i]],d[m+3*v[i]].........{for(int j=m+v[i];j<=MAX_V;j+=v[i]){if(d[j]<d[j-v[i]]+v[i]&&num[j-v[i]]<k[i]){d[j]=d[j-v[i]]+v[i];num[j]=num[j-v[i]]+1;}}}}int ant=0;for(int i=0;i<=MAX_V;i++){if(ant<d[i]){ant=d[i];}}printf("%d\n",ant);}return 0;}








原创粉丝点击