0-1背包问题通常可以归纳为:给定一些确定价值与质量的物品,在规定的总重量的约束条件下,合理的选择使得选择的物品使得总价值最大。
对这个问题进行分析,如果使用暴力枚举的方法,每一个物品有两种可能,不妨令物品是否在背包中的状态为
对于这种情况而言,它的暴力解法需要的时间复杂度是O(2^n),因此,下面介绍使用动态规划的算法来对这个背包问题进行解决。
首先,我们先定义一个二维数组:dp[ i ][ j ],这个二维数组我们赋予它的意义为:限重为j的情况下,放入前面i个物品的最大价值。
当我们开始考虑这件物品是否需要放下的情况时,会出现两种不同的情况:
1.不放入第i件物品。
2.在可以放下的前提下,放入第i件物品。
然后,我们可以思考dp[ i ][ j ]与dp[ i-1 ][ j ]和dp[ i-1 ][ j-weight ]+value的关系。
毫无疑问,dp [ i ][ j ]=max(dp[ i-1 ][ j ],dp[ i-1 ][ j-weight ]+value).
得到递推关系后,我们再开始进行对dp[ ] [ ]数组进行初始化。
当i=0,1,2...n,j=0时,dp[ i ][ j ]=0。这种情况代表了允许放入重量为0时的情况。毫无疑问,这种情况下dp[ i ][ j ]=0。当i=0时,i-1<0,无法进行计算。所以我们根据实际来规定——dp[0][j]的值当j>=weight[0]时,dp[0][j]=value(0),即当允许的重量大于等于第0个物品的重量时,dp[i][j]的值为第0个货物的价值。
下面用一个具体的问题来具体分析。
假设一群宝石的质量和价值如下图所示:
并规定背包允许放下的最大重量为9。我们可以通过递推公式画出表格:
具体的java实现:
package test;
public class dps {
public static void main(String args[])
{
int []value= {1,2,3,4};
int []weight= {2,3,4,5};
int bigweight=9;
int [][]dp; dp=new int[value.length][bigweight+1];
for(int i=0;i<value.length;i++)
{
dp[i][0]=0;
}
for(int j=weight[0];j<bigweight+1;j++)
{
dp[0][j]=value[0];
}
for(int i = 1; i < value.length; i++) { // 遍历物品
for(int j = 0; j <= bigweight; j++) { // 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
for(int i1=0;i1<value.length;i1++)
{
for(int j=0;j<bigweight+1;j++)
{
System.out.print(dp[i1][j]);
}System.out.print("\n");
}
}
}
具体的运行结果如图所示:
与上图的表格一致,说明算法无误。 时间复杂度为O(N^2)。