背包问题复习2
2017-08-07 17:01
218 查看
背包问题复习2
1.对于数据量变大的01背包问题
题目:想法:首先这题的size和bag都很大,如果直接用动态规划套原来的模板肯定不行,但是我们发现对于value的值比较小。那么我们不妨反过来想这个问题,我们记录对于选到第n个物品,价值达到j的重量最小的情况。这样最后达到的目标肯定是装的最多的。
code:
#include<iostream> #include <memory.h> #define INF 0xfffffff using namespace std; int value[1000],bag[1000]; int dp[1000][1000]; int main(void){ int n,size,ans; cin>>n>>size; for(int i=0;i<n;i++){ cin>>value[i]>>bag[i]; } fill(dp[0],dp[0]+1000,INF); dp[0][0]=0; for(int i=0;i<n;i++){ for(int j=0;j<=999;j++){ if(j<value[i]){ dp[i+1][j]=dp[i][j]; //如果本身该物品的价值就超过了需要的价值那么肯定不用选了 } else{ dp[i+1][j]=min(dp[i][j],dp[i][j-value[i]]+bag[i]); //总是选择让重量最小的达到该价值的选择方案 } } } for(int i=0;i<=999;i++){ //遍历n行的数组找到size下最大的i,也就是满足size的情况下的总价值 if(dp [i]<=size){ ans=i; } } cout<<ans<<endl; }
2.多重部分和问题
普通解法:不断迭代,用dp[i+1][j]表示用前i个数相加能否得到j。如果可以该单元为1,否则为0。#include <iostream> using namespace std; int num[1000],able[1000]; bool dp[1000][1000]; int main(void){ int n,sum; cin>>n>>sum; dp[0][0]=1; for(int i=0;i<n;i++){ cin>>num[i]; } for(int i=0;i<n;i++){ cin>>able[i]; } for(int i=0;i<n;i++){ for(int j=0;j<=sum;j++){ for(int k=0;k<=able[i]&&k*num[i]<=j;k++){ dp[i+1][j]|=dp[i][j-k*num[i]]; } } } cout<<dp [sum]<<endl; }
优化:但是实际上使用dp来做布尔运算是十分浪费的,我们可以用dp来保存多一点的东西以便于后续的优化计算。
poj 1742
code:#include <iostream> using namespace std; int a[101],m[101]; int dp[100005]; int main(void){ int n,K; while(cin>>n){ memset(a,0,101); memset(m,0,101); memset(dp,-1,sizeof(dp)); dp[0]=0; int count=0; cin>>K; if(n==0&&K==0){ break; } for(int i=0;i<n;i++){ cin>>a[i]; } for(int i=0;i<n;i++){ cin>>m[i]; } for(int i=0;i<n;i++){ for(int j=0;j<=K;j++){ if(dp[j]>=0){ dp[j]=m[i]; } else if(j<a[i]||dp[j-a[i]]<=0){ dp[j]=-1; } else{ dp[j]=dp[j-a[i]]-1; } } } for(int i=1;i<=K;i++){ if(dp[i]>=0){ count++; } } cout<<count<<endl; } }
相关文章推荐