01背包问题

背包问题

背包 : 空间
// — 用什么来记录
数组 ??? arr[] 需要记录的东西 重量, 价值, 让下标来记录物品id

首先 使用动态规划, 我们就要明白动态规划的特点, 对于背包问题
那么首先是划分子问题, 最小的子问题就是, 当只有一个物体的时候, 你是
怎么拿的, 肯定是根据背包容量(capa)的大小, 当前物体能够装下就装啊


其次接下来存在两个物品时, 你需要怎么拿, 如果容量能够装下两个物品,那就都拿
除非该物品的价值是0(那就不需要放进来了嘛,以为我闲的), 否则就只能装下其中的
一个那么,就需要怎么办呢 比大小嘛 ok到这里 你可以尝试自己想想怎么写,动手画画也不错哦
物品背包关系展示

id = 0; 的物品

  1. 判断重量 : w[id] < capa
    yes no
    capa -= w[id] 0
    value += values[id] 0
    id = 1; 的物品
  2. 判断重量 : w[id] < capa
    yes no
    capa -= w[id] w[id]
    value += values[id] values[id]
  • 当出现第一个物品的时候, 只要容量能够装下该物品那么就 拿,并且由于只有一个物品, 所以装下的价值就是物品当前的价值
    第一个for循环就是初始化只有一个物品时,数组中元素的值

  • 当物品的质量大于背包容量时就不拿,如果物体的质量小于背包的容量时,就对拿和不拿的价值进行比较

  1. Math.max(arr[i - 1][j] , arr[i - 1][j - w[i] + v[i]]);

  2. arr[i - 1][j] : 如果不拿, 那么就使用的是上一个物品拿不拿的价值啊 , 而i是记录当前物品的id
    -1 自然就是上一个物品的id, j表示容量,所以就是上一个物体当前容量所能获得的最大价值,就是arr[i-1][j]的值了

  3. arr[i - 1][j - w[i]]: arr[i-1]表示的是上一个物品 [j - w[i]] 表示的是当前的容量装上当前的物品后剩余的容量, 该容量能够装下的最大的价值是

  4. v[i] : 就是当前物品的价值了

  5. 那么 arr[i - 1][j - w[i]] + v[1] 就是装上当前物品后最大的价值

  6. max : 最大的价值就是存在当前物品和之前的其他物品时能够装入的最大价值
    如果你还没怎么明白, 看看这位大佬的解释
    掘金图文详解

function findMaxValues (capa,  w, v){
    let arr = [[]];
    for (let index = 0; index <= capa; index++) {
        if(index < w[0]){
            arr[0][index] = 0;
        }else{
            arr[0][index] = v[0]; // 记录价值, 下标index记录的是物体不同的容量背包大小,在该容量下能够获得的最大价值就是这个二维数组元素的值, 【0】是物品
        }
    }

    for (let j = 0; j <= capa; j++) {
       for (let i = 1; i <= w.length - 1; i++) {
           if(!arr[i]){
               arr[i] = [];
           }

           if(j < w[i]){
               arr[i][j] = arr[i - 1][j];
           }else{
               arr[i][j] = Math.max(arr[i-1][j], arr[i -1][j - w[i]] + v[i]);
           }
       }
    }
    console.log(arr);
    return arr[w.length - 1][capa];
}

console.log(findMaxValues(capacity, weights, values));

其实原理是一样的, 而且上面的解法看着 结构清晰些, 下面的在绕你

// ********************** 背包问题 (下面这个是书上的解法)
function knapSack(capacity, weights, values, n) {
    const kS = []; // 
    for (let i = 0; i <= n; i++) { // {1}
        kS[i] = [];
    }
    for (let i = 0; i <= n; i++) { // 从n可以看出他是多初始化了一个物品0 即当没有物品时,
        for (let w = 0; w <= capacity; w++) {
            if (i === 0 || w === 0) { // {2} 所有的价值都是0
                kS[i][w] = 0;
            } else if (weights[i - 1] <= w) { // {3} // 走到这里其实i都是从1开始的, i-1就是 i物品对应的当前重量和价值的下标索引
                const a = values[i - 1] + kS[i - 1][w - weights[i - 1]];// 拿到该物品后所产生的最大价值
                const b = kS[i - 1][w]; // 当前容量的前一个物品 能够获得的最大价值
                kS[i][w] = a > b ? a : b; // {4} max(a,b)  // 获得是否拿当前物品的最大价值,即当前容量下, 存在当前物品和之前的物品,能够取得的最大价值
            } else {
                kS[i][w] = kS[i - 1][w]; // {5}
            }
        }
    }
    findValues(n, capacity, kS, weights, values); // {6} 增加的代码
    console.log(kS);
    return kS[n][capacity]; // {7}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值