zoukankan      html  css  js  c++  java
  • 多重背包

    题目大意:



    这个问题和 01背包 问题很相似,我们也可以依然采取 01背包 的状态定义

    dp[i][j] 代表前 i 个物品 容量为 j 的背包的最大价值

    那么状态转移方程也就出来了:

    dp[i][j] = max(dp[i][j],dp[i-1][j-k*v[i]]+w[i])        (k 可以为 0,1,2,3...s[i])

    int dp[110][110],v[110],w[110],s[110];
    
    int main() {
        int n,m;
        cin >> n >> m;
        for (int i = 1;i <= n;i++) {
            cin >> v[i] >> w[i] >> s[i];
        }
        for (int i = 1;i <= n;i++) {
            for (int j = 1;j <= m;j++) {
                for (int k = 0;k <= s[i];k++) {
                    if (k * v[i] <= j)
                        dp[i][j] = std::max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);
                }
            }
        }
        cout << dp[n][m] << endl;
        return 0;
    }

    这种朴素的方法的时间复杂度 和 空间复杂度都很高,所以一般不采取

    我们可以先采取和 01背包 一样的滚动数组的方式去优化一下

    简单优化:

    和 01背包 一样,我们也应该从大往小更新,理由和 01背包 也是一样的,这里就不多说了

    int dp[1010];
    
    int main() {
        int n,m;
        std::cin >> n >> m;
        for (int i = 1;i <= n;i++) {
            int v,w,s;
            std::cin >> v >> w >> s;
            for (int j = m;j >= 0;j--) {
                for (int k = 1;k <= s && k * v <= j;k++) {
                    dp[j] = std::max(dp[j],dp[j-k*v]+k*w);
                }
            }
        }
        std::cout << dp[m] << std::endl;
        return 0;
    }

    二进制优化:拆解成多个 01背包问题

    其实就是把 件数s 进行二进制的拆分 ,因为这样拆分之后的数 可以表示 [0~s] 之间的任何数  (自行证明)

    int dp[2010];
    
    struct Node {
        int v,w;
    };
    std::vector<Node> vec;
    
    int main() {
        int n,m;
        std::cin >> n >> m;
        for (int i = 1;i <= n;i++) {
            int v,w,s;
            std::cin >> v >> w >> s;
            for (int k = 1;k <= s;k <<= 1) {
                s -= k;
                vec.push_back({k*v,k*w});
            }
            if (s > 0)
                vec.push_back({s*v,s*w});
        }
        for (auto i:vec) {
            for (int j = m;j >= i.v;j--) {
                dp[j] = std::max(dp[j],dp[j-i.v]+i.w);
            }
        }
        std::cout << dp[m] << std::endl;
        return 0;
    }

    这个时候的算法复杂度以及足够优秀了  ,当然还有一种更加优秀的做法就是 采取单调队列优化 (自行搜索)

  • 相关阅读:
    88. 合并两个有序数组
    680. 验证回文字符串 Ⅱ
    345. 反转字符串中的元音字母
    633. 平方数之和
    分支程序设计
    scanf函数(初学者)
    输入与输出(初学者)
    C语句详细(初学者)
    算术运算符和算术表达式(初学者)
    变量赋值(初学者)
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/12250417.html
Copyright © 2011-2022 走看看