动态规划解决背包问题

现有题:有A,B,C,D这四物品,其重量分别为3,4,1,5。其价值分别是10,40,30,20。有一个能装重量为6的背包,问怎么装物品能使背包在不超过其承重范围而获得最大价值。
解决这个问题最快捷的方式是运用动态规划法。什么是动态规划:把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。
求这道题可以将重量6分隔成为6种重量。分别去求装满0,装满1…等各种情况。最终就可以的出装到重量6时的最佳装法。
可以列出表格进行分析:

~ 0 1 2 3 4 5 6
A(3,10)
B(4,40)
C(1,30)
D(5,20)

从第一行开始,第一列为用A装满重量为0的背包,此时这种情况是,你只能不装东西,其价值就为0。依次往后走,直到到了重量为3的背包,此时你正好可以将A放入背包中,其价值为10,依次往最后到重量6,背包都能装下物品A,且此时的背包价值为10。

~ 0 1 2 3 4 5 6
A(3,10) 0 0 0 10 10 10 10
B(4,40)
C(1,30)
D(5,20)

从第二行开始,用如上的方法将B装入背包中。此时要注意的是当背包重量为3时,是可以装下A,但是装不下B,所以此时的背包的最大价值是10。从重量4开始,可以装下B,此时B的价值是40,比装下物品A的价值还要大所以只装物品B,依次继续。

~ 0 1 2 3 4 5 6
A(3,10) 0 0 0 10 10 10 10
B(4,40) 0 0 0 10 40 40 40
C(1,30)
D(5,20)

从第三行开始,物品C是在背包重量为1的时候开始可以被装下的,此时值为30。

~ 0 1 2 3 4 5 6
A(3,10) 0 0 0 10 10 10 10
B(4,40) 0 0 0 10 40 40 40
C(1,30) 0 30 30 30 40 70 70
D(5,20)

按照上述方法最终可得到表格

~ 0 1 2 3 4 5 6
A(3,10) 0 0 0 10 10 10 10
B(4,40) 0 0 0 10 40 40 40
C(1,30) 0 30 30 30 40 70 70
D(5,20) 0 30 30 30 40 70 70

所以最大的价值是70。
代码如下:

$weight = 5;  //背包重量
$total = 4;   //物品种类
$arr = [['A', 3, 10], ['B', 4, 40], ['C', 1, 30], ['D', 5, 20]]; //物品数组
//构造不同重量的背包的价值数组
$values = array_fill(0, $weight + 1, 0);
//构造重量所属物品数组
$items = array_fill(0, $weight + 1, 0);

for ($i = 0; $i < $total; $i++) {
    for ($j = $arr[$i][1]; $j <= $weight; $j++) {
        //各个阶段的袋子存入物品后剩余重量
        $left_weight = $j - $arr[$i][1];
        //出入物品后新的价值
        $new_value = $arr[$i][2] + $values[$left_weight];
        //如果当前的最新价值大于历史最大价值时,替换values数组所属重量的值
        if($new_value > $values[$j]) {
            $values[$j] = $new_value;
            //记录下次物品
            $items[$j] = $i;
        }
    }
}
echo "最大价值是 {$values[$weight]}
\n"
; echo "物品名称 重量 价值
\n"
; //找出最大价值所属各个物品,从下往上(重量)递推 for ($j = $weight; 1 <= $j; $j = $j - array[$items[$j]][1]) { echo array[$items[$j]][0] . " " . array[$items[$j]][1] . " " . array[$items[$j]][2] . "
\n"
; }

你可能感兴趣的:(PHP)