问题描述:
n种物品,每种一个。第i种物品的体积为Vi,重量为Wi。选一些物品装到容量为C的背包,使得背包内物品不超过C的前提下,重量最大。
问题分析:
声明一个f[n][c]的数组。f[i][j]表示把前i件物品都装到容量为j的背包所获得的最大重量。
当 j < v[i] 时,背包容量不足以放下第 i 件物品,f[ i ][ j ] = f[ i-1 ][ j ]
当j>=v[i] 时,背包容量可以放下第 i 件物品。
如果拿,f[ i ][ j ]=f[ i-1 ][ j-v[ i ] ] + w[ i ]。 这里的f[ i-1 ][ j-v[ i ] ]指的就是考虑了i-1件物品,背包容量为j-v[i]时的最大价值,也是相当于为第i件物品腾出了v[i]的空间。
如果不拿,f[ i ][ j ] = f[ i-1 ][ j ]
比较这两种情况那种价值最大。
每种物品只有两种情况,拿或者不拿,可以用一个标记数组来记录。
另起一个 flag[ ] 数组,flag[i]=0表示不拿,flag[i]=1表示拿。
f[n][c]为最优值,如果f[n][c]=f[n-1][c] ,说明有没有第n件物品都一样,则flag[n]=0 ; 否则 flag[n]=1。当flag[n]=0时,由f[n-1][c]继续构造最优解;当flag[n]=1时,则由f[n-1][c-w[i]]继续构造最优解。
模板:
memset(f, 0, sizeof(f));
for (int i=1; i<=n; i++){
for (int j=0; j<=c; j++){
if (j>=v[i])
f[i][j]=max(f[i-1][j], f[i-1][j-v[i]]+w[i]);
else
f[i][j]=f[i-1][j];
}
}
void traceback()
{
for(int i=n;i>1;i--)
{
if(f[i][c]==f[i-1][c])
flag[i]=0;
else
{
flag[i]=1;
c-=v[i];
}
}
flag[1]=(f[1][c]>0)?1:0; 把i等于1的情况放在for里面也可以, 因为[0][j]都是0
}
附滚动数组优化:
for (int i=1; i<=n; i++){
for (int j=c; j>=0; j--){
if (j>=v[i])
f[j]=max(f[j], f[j-v[i]]+w[i]);
}
}
参考链接:https://blog.csdn.net/xp731574722/article/details/70766804