在上一篇文章中,简单分析了0-1背包问题,这篇接着简单分析下完全背包问题。
完全背包的问题形式如下:有一背包,只能装重量为V的物品,有n个的物品,这些物体体积为w,价值为v,在每个物品最多可以装无线个的情况下,怎么装物品可以让背包中的物品价值最大。完全背包问题与0-1背包相似,不同的是:0-1背包问题汇总,每个物品最多只能装1个;而在完全背包中,每个物品在不超过背包限重的情况下,可以装无数个。因此,完全背包的分析思路与0-1背包类似,不同之处在于状态转移公式的推导。
与0-1背包问题分析类似,可以先定义一些变量,来辅助分析。具体为:value[ i ]表示第i个物品的价值,weight[ i ]表示第i个物品的体积,dp[ j ]表示当前背包容量为j时,最佳组合对应的价值。为方便分析,设定物品个数为5,背包重量限制为20,示例数据如下:
体积(weight) | 2 | 3 | 4 | 5 | 9 |
价值(value) | 3 | 4 | 5 | 8 | 10 |
分析步骤如下:
1、如果按照上篇文章的方式做,构建一个二维数组,就需要三层for循环,肯定不是一个好的解决方法。此时可以用一维数组dp[ ]直接来存储value,进而用两层for循环解决该问题。
2、以dp[ j ],即背包可装重量为j的状态来进行分析(i为物品种类)。此时可能进行的动作有如下几种:
1>再装入一件相同物品价值大,即dp[ j ] = dp[ j+1 ];
2>再装入一件其他物品价值大,即dp[ j ] = dp[ j-weight[ i ] ] + value[ i ]。
寻找最大价值的过程,就是不断更新dp数组的过程,直到数组中最后一个值填完,即最大value值。
Java代码如下:
static int weight[ ]={0,2,3,4,5,9}; //每个商品容量
static int value[ ]={0,3,4,5,8,10}; //每个商品价值
static int NUM = weight.length; //商品种类。包含第0个这个特殊值
static int CAP = 21; //总可用容量+1,包含第0个这个特殊值,所以总容量是20
//不断填充value数组
int dp[] = new int[ CAP ];
for(int i=1;i<NUM;i++){
for(int j=weight[ i ];j<CAP;j++){
dp[ j ] = Math.max(dp[ j ],dp[ j-weight[ i ] ]+value[ i ]);
}
}
//数组最后一个值,即为最大value值
System.out.println(dp[ 20 ]);