初学动态规划——背包问题

学习一些算法,发现在动态规划的背包问题卡了很久 

先是阅读了一下这篇博客https://www.cnblogs.com/raichen/p/5772056.html

学了一些理论知识,这里不再论述,重点解决一下背包问题

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 

f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。

将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f [i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。 

看到这里,有点懵逼,这个f[i][v]到底怎么求? 再看上面博客里的C++代码,还是晕

后来再查阅了资料,找到这个图

设置的数据是 

var bagName = ['a', 'b', 'c', 'd', 'e'];

var weightArr = [2, 2, 6, 5, 4];

var valueArr = [6, 3, 5, 4, 6];

这个表怎么看捏? 列坐标的1到10表示V,这里相当于变动的,不是一开始看到题目我们就定住的,至于为什么变动,就是为了可以拿到比较值去判断。

b3的值是3,表示的就是当V为3时,由bcde中可以选取装下的价值最大值,直接可以判断拿到b时,价值w[i]最大。以此类推,表中取得的信息就是这个意思。

这个表先亮出来是为了解决问题,寻找规律,也就是一开始所说的那段话。

判断第i件物品放入后的最大值,就只有两种情况,一种就是假设不拿这件物品,此时的w1[i]就是之前放入第i-1件物品(并不是都放入,只是部分)取得的最大值;而如果放入该物品,那么就要用V减去这件物品的费用(因为假设它被放入了),剩下的空间拿去放入第i-1件物品获得的最大值w2[i],那么此时就来比较w1[i]和w2[i]+item.value(这里别忘记加入假设已放入的物品的value),谁大,这个最大值就是指谁。

再加上边缘判断,就能得出要求的最大值,然后返回来根据item.value求得对应拿入什么物件,就达到题目要求。

读到这里看不到的话,先看这篇https://blog.csdn.net/mu399/article/details/7722810,代码注释的话 建议往下看

具体代码如下:

var bagName = ['a', 'b', 'c', 'd', 'e'];
var weightArr = [2, 2, 6, 5, 4];
var valueArr = [6, 3, 5, 4, 6];
var bagItems = [];
// 将三个数组关联成对象数组好处理
bagName.forEach((item, index) => {
    bagItems.push({
        name: item,
        weight: weightArr[index],
        value: valueArr[index]
    })
})
bagItems = bagItems.reverse();
console.log(bagItems);
getAnswer(10,bagItems);
// 求解的函数
function getAnswer(bagSize, bagItems){
var bagMax = [];  // 创建一个二维数组 用来存储与比较
for(let i=0;i<bagItems.length;i++)
{
    bagMax[i] = [0];   
}
     
  for(let i=1; i<=bagSize; i++)   // 这里的“总重量”是变化的
  {                                  
    for(let j=0; j<bagItems.length; j++){ 
        var item = bagItems[j];  
        if(item.weight > i){  // 如果拿到的东西item的重量都比“总容量”大, 那可以知道这个item放不进去
            if(j == 0){
              bagMax[j][i] = 0  // j==0时,说明前面没有东西放 当然bagMax[j][i]要存0
            } else {
              bagMax[j][i] = bagMax[j-1][i] //j不为0时,那就存之前的存储的“最大值”
            }
        }else{             // 如果拿到的东西item的重量都比“总容量”小, 核心就在这里啦
          if(j == 0){      //当然 对于j==0的情况,前面没有最大值,把东西放进去就好
             bagMax[j][i] = item.value  
          }else{  // 如果东西不是第一个, 那就得对 前j-1个东东获得最大值 bagMax[j-1][i](即不放这个东东) 与 放入这个东东作比较
            var temp = bagMax[j-1][i-item.weight] + item.value  // 为什么要存那么多个“最大值”去对应 就是这里用到 这个temp表示当前item已经放入,剩下的空间去找到最大值,然后合并
            bagMax[j][i] = temp > bagMax[j-1][i] ? temp : bagMax[j-1][i]
          }
        }
    }

  }
  console.log(bagMax); //打印数据表看一下
//find answer
    var answers=[];
    var curSize = bagSize;
    for(let i=bagItems.length-1;i>=0;i--)
    {
        item = bagItems[i]  
        if(curSize==0)
        {
            break;
        }
        if(i==0 && curSize > 0) //到最后一个值如果curSize还有 说明这个也是组成最大值的一份子
        {
            answers.push(item.name);
            break;
        }
        if(bagMax[i][curSize]-bagMax[i-1][curSize-item.weight]==item.value) //例如拿含有abcd的最大值和含有abc的最大值相减,差值如果为d的value,说明它在里面
        {
            answers.push(item.name);
            curSize -= item.weight;
        }
    }
    console.log(answers);
}

运行结果为: 

文章的思路借鉴

动态规划之01背包问题(最易理解的讲解)https://blog.csdn.net/mu399/article/details/7722810

https://www.cnblogs.com/raichen/p/5772056.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值