dp之多重背包poj1276
题意:有现今cash,和n种钱币,每种钱币有ni个,价值为di,求各种钱币组成的不超过cash的最大钱数.......
思路:二进制拆分转化为01背包,或者转化为完全背包都是可以的。
反思:这个题目我wa两次,是应为我把判断cash==0||n==0放得太前,以致于后面的数据木有输入
wa代码:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; int dp[110000],t[30000],s[2000][2]; int main() { int cash,n; while(scanf("%d%d",&cash,&n)>0) { if(cash==0||n==0) //错在这里,放的太前 { printf("0\n"); continue; } int cnt=0; for(int i=1;i<=n;i++) { scanf("%d%d",&s[i][0],&s[i][1]); int k=1; while(s[i][0]-k>0) { t[cnt++]=k*s[i][1]; s[i][0]-=k; k*=2; } t[cnt++]=s[i][0]*s[i][1]; } memset(dp,0,sizeof(dp)); for(int i=0;i<cnt;i++) { for(int j=cash;j>=t[i];j--) if(dp[j]<dp[j-t[i]]+t[i]) dp[j]=dp[j-t[i]]+t[i]; } printf("%d\n",dp[cash]); } return 0; }
ac代码,二进制拆分:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; int dp[110000],t[30000],s[2000][2]; int main() { int cash,n; while(scanf("%d%d",&cash,&n)>0) { int cnt=0; //memset(t,0,sizeof(t)); for(int i=1;i<=n;i++) { scanf("%d%d",&s[i][0],&s[i][1]); int k=1; if(s[i][0]==0||s[i][1]==0) continue; while(s[i][0]-k>0) { t[cnt++]=k*s[i][1]; s[i][0]-=k; k*=2; } t[cnt++]=s[i][0]*s[i][1]; } memset(dp,0,sizeof(dp)); for(int i=0;i<cnt;i++) { for(int j=cash;j>=t[i];j--) if(dp[j]<dp[j-t[i]]+t[i]) dp[j]=dp[j-t[i]]+t[i]; } printf("%d\n",dp[cash]); } return 0; }
ac代码,转换为完全背包:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; int dp[110000],num[100100],s[2000][2]; int main() { int cash,n; while(scanf("%d%d",&cash,&n)>0) { int cnt=0; for(int i=1;i<=n;i++) { scanf("%d%d",&s[i][0],&s[i][1]); } memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { memset(num,0,sizeof(num)); for(int j=s[i][1];j<=cash;j++) if(dp[j]<dp[j-s[i][1]]+s[i][1]&&num[j-s[i][1]]<s[i][0]) { dp[j]=dp[j-s[i][1]]+s[i][1]; num[j]=num[j-s[i][1]]+1; } } printf("%d\n",dp[cash]); } return 0; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。