zoukankan      html  css  js  c++  java
  • 背包问题解题方法总结

    最近在牛客刷题遇到好几道背包问题,索性这两天集中火力刷了一些这类的题。这里总结一下0-1背包完全背包多重背包三种基本的背包问题的解题套路。(均基于动态规划的思想)

    0-1背包

    题目:有 N 件物品和容量为 W 的背包。第 i 件物品的重量为 w_i,价值为 v_i,求将不超过背包容量的物品装入背包能得到的最大价值。

    特点,每件物品的数量只有一个,可以选择放或不放某件物品。

    dp[i][j]表示将前 i+1 件总重量不超过 j 的物品放入背包能获得的最大价值,则可以用以下的转移方程来表示这个过程:

    [dp[i,j] = max(dp[i - 1, j], dp[i-1, j-w[i]] + v[i]) ]

    注意到dp数组第i行的值更新只跟 i-1 行有关,因此可以通过滚动数组或者反向更新的方式优化一下空间复杂度,在动态规划解题的时候这是一种常用的空间复杂度优化方式。优化后的代码如下:

    for(int i = 0; i < N; i++){
        // 注意到这里dp需要从后往前更新,避免更新前就把旧值覆盖
        // 从实际意义上来说,因为每件物品只有一个,从后向前更新保证了更新是在还没放入过当前物品的前提下进行的
        for(int j = W; j >= w[i]; j--){  
            dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
        }
    }
    

    完全背包

    题目:有 N 种物品和容量为 W 的背包。第 i 种物品的重量为 w_i,价值为 v_i,每种物品的数量无限。求将不超过背包容量的物品装入背包能得到的最大价值。

    特点:每种物品的数量无限多。

    考虑到每种物品的数量无限。用 dp[j] 表示在重量不超过 j 的情况下背包中物品可以达到的最大价值,则转移方程如下:

    [dp[j]=max(dp[j], dp[j-w[i]]+v[i]) ]

    核心代码如下:

    for(int i = 0; i < N; i++){
        for(int j = w[i]; j <= W; j++){    // 这里和0-1背包不同
            dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
        }
    }
    

    注意内层for循环是从前向后更新dp数组的,这是唯一和上面的0-1背包问题区别的地方。原因在于,题目中每种物品的数量无限多,在放入一件物品 i 时,要考虑之前已经放过物品 i 的情况。

    多重背包

    题目:有 N 种物品和容量为 W 的背包。第 i 种物品的数量有n_i个,每个物品重量为 w_i,价值为 v_i,每种物品的数量无限。求将不超过背包容量的物品装入背包能得到的最大价值。

    特点:每种物品的数量不止一个,但有限。

    基本的多重背包问题状态转移方程如下:

    [dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]), 0leq k leq n[i] ]

    核心代码如下:

    for(int i = 0; i < N; i++){
        for(int j = W; j >= w[i]; j--){  
            for(int k = 1; k <= n[i]; k++){
                if(j < k * w[i])  break; 
                dp[j] = Math.max(dp[j], dp[j - w[i] * k] + v[i] * k);
            }
        }
    }
    

    一些背包问题的题目

    上面讨论的三种情况只是最基本的背包问题,实际刷题过程中会遇到这些基本问题的变体,例如需要背包正好装满、求最小的物品件数、求装包的方案数等等。这里整理一些题目,后面遇到了持续更新~

    0-1背包类题目

    考试策略
    篮球队 - 求方案数
    牛妹的春游 - 最小花费,多个条件,初始值限制
    服务部署 - 多重条件

    完全背包类题目

    换零钱 - 求总方案数
    最少数量货物装箱问题 - 物品件数最小,恰好装满
    拼凑面额 - 求方案数

    多重背包类题目

    乔乔的包

  • 相关阅读:
    Codeforces1101G (Zero XOR Subset)-less 【线性基】【贪心】
    Codeforces1101F Trucks and Cities 【滑动窗口】【区间DP】
    HDU4651 Partition 【多项式求逆】
    BZOJ2554 color 【概率DP】【期望DP】
    codeforces1101D GCD Counting 【树形DP】
    codechef EBAIT Election Bait【欧几里得算法】
    BZOJ2434 [NOI2011] 阿狸的打字机 【树链剖分】【线段树】【fail树】【AC自动机】
    codeforces1093G Multidimensional Queries 【线段树】
    BZOJ3277 串 【后缀数组】【二分答案】【主席树】
    AHOI2013 差异 【后缀数组】
  • 原文地址:https://www.cnblogs.com/rezero/p/13347670.html
Copyright © 2011-2022 走看看