1.首先看一下这个方程,这是背包问题的精髓所在
01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值。
Pi表示第i件物品的价值。
决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中吗 ?这个需要比较一下。
2.问题描述
有n中物品和一个能承受最大重量c的背包,物品i的重量的wi,其价值为vi,问应该如何选择装入的物品,使得背包中的物品的总价值最大。对于每个物品,我们只有选择拿还是不拿两种选择,不能选择装入某物品的一部分,也不能装入同一种物品多次。
3.例子
有a,b,c,d,e这5种物品,它们的重量分别为2,2,6,5,4,它们的价值分别为6,3,5,4,6,现在给个能承重10的背包。
4.画图
为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意思是当有物品e时,有个能承重为2的背包,那么这个背包的最大价值为0,因为e物品的重量是4,背包装不下。
对于d2单元格,表示物品有e、d时,有承重为2的背包,所能装下的最大价值,仍然是0,因为e、d都不是这个背包能装下的。
那对于承重为8的背包,a8=15,这个怎么理解?
根据01背包的状态转换方程,需要考察两个值,一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;在这里,f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包。
简单的理解就是我放入当前物品的价值和不放当前物品的价值比较一下,哪个价值大,我就采取哪种方法。
建议上面的图要亲手画一遍,方便理解。
5.代码部分
// f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }//背包可以装最大的重量总结的博客来自http://blog.csdn.net/mu399/article/details/7722810
$w=10;
//这里有四件物品,每件物品的重量
$dx=array(2,2,6,5,4);
//每件物品的价值
$val=array(6,3,5,4,6);
//定义一个数组
$maxValue=array();
//初始化
for($i=0;$i<=10;$i++){
$maxValue[0][$i]=0;
}
for ($j=0;$j<=5;$j++){
$maxValue[$j][0]=0;
}
//Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
for ($j=1;$j<=5;$j++){
for($i=1;$i<=10;$i++){
$maxValue[$j][$i]=$maxValue[$j-1][$i];
//不大于最大的w=10
if($dx[$j-1]<=$w){
//这种情况是防止减去自身的重量后,成了负数
if(!isset($maxValue[$j-1][$i-$dx[$j-1]])) continue;
//f[i-1,j-Wi]+Pi( j >= Wi )
$tmp = $maxValue[$j-1][$i-$dx[$j-1]]+$val[$j-1];
//Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] } => 进行比较
if($tmp>$maxValue[$j][$i]){
$maxValue[$j][$i]=$tmp;
}
}
}
}
//打印这个数组,输出最右角的值是可以最大价值的
for ($j=1;$j<=5;$j++){
for ($i=1;$i<=10;$i++){
if ($maxValue[$j][$i]<10)
echo " ".$maxValue[$j][$i]." ";
else echo $maxValue[$j][$i]." ";
} echo "<br>";
}