动态规划解决背包问题

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

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

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

~0123456
A(3,10)00010101010
B(4,40)
C(1,30)
D(5,20)

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

~0123456
A(3,10)00010101010
B(4,40)00010404040
C(1,30)
D(5,20)

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

~0123456
A(3,10)00010101010
B(4,40)00010404040
C(1,30)0303030407070
D(5,20)

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

~0123456
A(3,10)00010101010
B(4,40)00010404040
C(1,30)0303030407070
D(5,20)0303030407070

所以最大的价值是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]}<br/>\n";
echo "物品名称 重量 价值<br/>\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] . "<br/>\n";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值