01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为C1,C2,…,Cn,与之相对应的价值为W1,W2,…,Wn.求解将那些物品装入背包可使总价值最大。
动态规划(DP):
1) 子问题定义:F[i][j]表示前i件物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值。
2) 根据第i件物品放或不放进行决策
其中F[i-1][j]表示前i-1件物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值;
而F[i-1][j-C[i]]+W[i]表示前i-1件物品中选取若干件物品放入剩余空间为j-C[i]的背包中所能取得的最大价值加上第i件物品的价值。
根据第i件物品放或是不放确定遍历到第i件物品时的状态F[i][j]。
设物品件数为N,背包容量为V,第i件物品体积为C[i],第i件物品价值为W[i]。
在0/1背包问题中,物体或者被装入背包,或者不被装入背包,只有两种选择。
循环变量i,j意义:前i个物品能够装入载重量为j的背包中
(n+1)*(m+1)数组value意义:value[i][j]表示前i个物品能装入载重量为j的背包中物品的最大价值
若w[i]>j,第i个物品不装入背包
否则,若w[i]<=j且第i个物品装入背包后的价值>value[i-1][j],则记录当前最大价值(替换为第i个物品装入背包后的价值)
计算最大价值的动态规划算法如下:
//
计算
for (i = 1 ;i < row;i ++ )
... {
for(j=1;j<col;j++)
...{
//w[i]>j,第i个物品不装入背包
value[i][j]=value[i-1][j];
//w[i]<=j,且第i个物品装入背包后的价值>value[i-1][j],则记录当前最大价值
int temp=value[i-1][j-w[i]]+v[i];
if(w[i]<=j && temp>value[i][j])
value[i][j]=temp;
}
}
for (i = 1 ;i < row;i ++ )
... {
for(j=1;j<col;j++)
...{
//w[i]>j,第i个物品不装入背包
value[i][j]=value[i-1][j];
//w[i]<=j,且第i个物品装入背包后的价值>value[i-1][j],则记录当前最大价值
int temp=value[i-1][j-w[i]]+v[i];
if(w[i]<=j && temp>value[i][j])
value[i][j]=temp;
}
}
即该段程序完成以下n个阶段:
1:只装入1个物品,确定在各种不同载重量的背包下,能够得到的最大价值
2:装入2个物品,确定在各种不同载重量的背包下,能够得到的最大价值
。。。
n:以此类推,装入n个物品,确定在各种不同载重量的背包下,能够得到的最大价值
3. 问题求解
确定装入背包的具体物品,从value[n][m]向前逆推:
若value[n][m]>value[n-1][m],则第n个物品被装入背包,且前n-1个物品被装入载重量为m-w[n]的背包中
否则,第n个物品没有装入背包,且前n-1个物品被装入载重量为m的背包中
以此类推,直到确定第一个物品是否被装入背包为止。逆推代码如下:
//逆推求装入的物品
j=m;
for(i=row-1;i>0;i--)
...{
if(value[i][j]>value[i-1][j])
...{
c[i]=1;
j-=w[i];
}
}
#include <stdio.h>
int main()
{
int i; // size of current item
int k; // value of current item
int num = 6; // number of items
int cap = 10; // capacity of our bag
int size[] = {-9999, 2, 3, 1, 4, 6, 5 }; // size of each item
int value[] = {-9999, 5, 6, 5, 1, 19, 7 }; // value of each item
// array of results
int F[num + 1][cap + 1];
// initialize first row and first col
for (i = 0; i <= cap; ++i)
F[0][i] = 0;
for (i = 1; i <= num; ++i)
F[i][0] = 0;
// dynamic programming for zeroOneBag problem
for (i = 1; i <= num; ++i)
{
for (k = 1; k <= cap; ++k)
{
F[i][k] = F[i-1][k];
if ( k >= size[i] && F[i-1][k-size[i]]+value[i] > F[i][k] )
F[i][k] = F[i-1][k-size[i]]+value[i];
}
}
// print result array
for (i = 1; i <= num; ++i)
{
for (k = 1; k <= cap; ++k)
printf("%3d ", F[i][k]);
printf("\n");
}
printf("max value = %d\n\n", F[num][cap]);
// print choose items
k = cap;
for (i = num; i > 0; --i)
{
if(F[i][k] > F[i-1][k])
{
printf("item: %d choosed, size: %d, value: %d\n", i, size[i], value[i]);
k -= size[i];
}
}
return 0;
}