题目链接:51nod1085 背包问题
问题描述:
有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过m的物品,求所有挑选方案中价值总和的最大值。
思路分析:
问题可以看做往一个载重量为m的背包中装入有限数量的物品,求装入物品的最大价值。这里物品的件数都为1,所以每个物品都只有两种选择,要么放入背包,要么不放。在背包容量为j时,对前i件物品来说,设它的最大价值为dp[i][j],它的最大价值状态转移公式为:
//当第i件物品比背包容量还大时,dp[i][j]等于前i-1件物品放入这个背包的最大价值。
dp[i][j]=dp[i-1] [j] (j<w[i])
//当第i件物品能放入背包时,分为两种情况,选择放和不放,不放的话和上面公式相同,放的话则背包容量减去第i件物品的重量再去装前i-1件物品,所得的最大价值加上第i件物品的价值。两种情况中较大的那种即为最优解。
dp[i][j]=max(dp[i-1] [j],dp[i-1] [j-w [i] ]+v[i]) (j>=w[i])
参考代码:
#include"cstdio" #include"algorithm" using namespace std; int N,W; int w[105],p[105]; int dp[10007][105]= {0}; void DP() { for(int i=1; i<=W; i++) for(int j=1; j<=N; j++) dp[i][j]=w[j]<=i?max(dp[i-w[j]][j-1]+p[j],dp[i][j-1]):dp[i][j-1]; } int main() { scanf("%d%d",&N,&W); for(int i=1; i<=N; i++) scanf("%d%d",&w[i],&p[i]); DP(); printf("%d\n",dp[W][N]); return 0; }
看了dd大牛的背包九讲后,对于01背包问题又有了更深层次的理解,从上面的分析可以看出,在每次更新dp数组时,总是在当前物品数-1的基础上的,能不能直接用一维数组来保存物品数-1时的值呢?只需把空间花费从大到小来构成for循环即可。
参考代码:
#include"cstdio" #include"cstring" #include"algorithm" using namespace std; int N,W; int w[105],p[105]; int dp[10005]; void DP() { for(int i=1;i<=N;i++) for(int j=W;j>0;j--) { dp[j]=w[i]<=j?max(dp[j-w[i]]+p[i],dp[j]):dp[j]; } } int main() { memset(dp,0,sizeof(dp)); scanf("%d%d",&N,&W); for(int i=1;i<=N;i++) { scanf("%d%d",&w[i],&p[i]); } DP(); printf("%d\n",dp[W]); return 0; }