学习一些算法,发现在动态规划的背包问题卡了很久
先是阅读了一下这篇博客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