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] }
//揹包可以裝最大的重量
$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>";
}
總結的博客來自http://blog.csdn.net/mu399/article/details/7722810