这一个星期以来,被背包问题搞得稀里糊涂。不过还是有收获。
对于一个01背包问题(01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为C1,C2,…,Cn,与之相对应的价值为W1,W2,…,Wn.求解将那些物品装入背包可使总价值最大。)我的理解如下:
首先二维数组:
for(int i = 0; i < n; i++) { for(int j = 0; j <= W; j++) {
//主要是状态转移方程
if(j < w[i])
{ dp[i+1][j] = dp[i][j]; //不够取的情况 } else { dp[i+1][j] =max{dp[i][j], dp[i][j-w[i]]+v[i]}; //够取的情况,以最大值决定取还是不取 } } }
一维数组
memset(f,0,sizeof(f)); for(int i=1;i<=n;i++)
{ scanf("%d%d",&V,&W); for(int j = C; j >= 0 ; j-- )//注意逆序,看注释 if(j >= V) f[j] = max ( f[j] , f[j-V] + W ); }
重点来了:
一 : f [ j ] 表示剩余空间为 j 时所能装的最大价值,而不是已经装的物品的价值
二 : 最让我迷惑的一点,当 i=1 时 f [ j ] 表示什么?
实际上 ,当 i = 1 时说明只有一个物品可选,即使后面还有物品(因为此时只考虑 i = 1 的情况),即使空间再大只能选一个。
还有就是。初始化时 i=0 时,数组 f 全部初始化为 0 。
三: 逆序,因为是一维数组,所以要保存类似于f[ i -1 ] [ j ]的效果只能逆序;否则顺序会导致f[ i ] [ j ]覆盖f[ i -1 ] [ j ] ,达不到状态转移效果。
另附:漫画动态规划