为了账号安全,请及时绑定邮箱和手机立即绑定

php实现01背包问题之动态规划

标签:
PHP

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;
}
/**
array(6) {
  [0]=>
  array(11) {
    [0]=>
    int(0)
    [1]=>
    int(0)
    [2]=>
    int(0)
    [3]=>
    int(0)
    [4]=>
    int(0)
    [5]=>
    int(0)
    [6]=>
    int(0)
    [7]=>
    int(0)
    [8]=>
    int(0)
    [9]=>
    int(0)
    [10]=>
    int(0)
  }
  [1]=>
  array(1) {
    [0]=>
    int(0)
  }
  [2]=>
  array(1) {
    [0]=>
    int(0)
  }
  [3]=>
  array(1) {
    [0]=>
    int(0)
  }
  [4]=>
  array(1) {
    [0]=>
    int(0)
  }
  [5]=>
  array(1) {
    [0]=>
    int(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>";
}
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 1
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消