• leetcode刷题(132)——完全背包问题思路理解


    完全背包问题描述

    有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。

    完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。

    同样leetcode上没有纯完全背包问题,都是需要完全背包的各种应用,需要转化成完全背包问题,所以这里还是以纯完全背包问题进行讲解理论和原理。

    版本1:这是朴素版本的,时间复杂度O(nm^2)

    #include
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int dp[N][N], v[N], w[N];
    
    int main(){
        cin >> n >> m;
        for(int i = 1; i <= n; i ++ )
            cin >> v[i] >> w[i];
    
        for(int i = 1; i <= n; i ++ )
            for(int j = 0; j <= m; j ++ )
                for(int k = 0; k * v[i] <= j; k ++ )
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);
        cout << dp[n][m] << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    版本2:这个就是把上面版本的第三重循环优化掉,优化的原理就是:
    dp[i][j - v] = max(dp[i - 1][j - v], dp[i - 1][j - 2 * v] + w, dp[i - 1][j - 3 * v] + 2 * w, …);
    而我们需要的dp[i][j]的状态表示是:
    dp[i][j]= max(dp[i - 1][j], dp[i - 1][j - v] + w, dp[i - 1][j - 2 * v] + 2 * w, dp[i - 1][j - 3 * v] + 3 * w);
    将每一项一一比对,我们可以得到下列状态表示:
    dp[i][j] = max(dp[i - 1][j], dp[i][j - v] +w);

    #include
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int dp[N][N], v[N], w[N];
    
    int main(){
        cin >> n >> m;
        for(int i = 1; i <= n; i ++ ){
            int v, w;
            cin >> v >> w;
            for(int j = 0; j <= m; j ++ ){
                dp[i][j] = dp[i - 1][j];
                if(j >= v)
                    dp[i][j] = max(dp[i][j], dp[i][j - v] + w);
            }
        }
        cout << dp[n][m] << endl;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    版本3:对代码进行等价变形。对照01背包的代码,就是将第二个循环从小到大进行枚举即可。

    #include
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int dp[N];
    
    int main(){
        cin >> n >> m;
        for(int i = 1; i <= n; i ++ ){
            int v, w;
            cin >> v >> w;
            for(int j = v; j <= m; j ++ ){
                    dp[j] = max(dp[j], dp[j - v] + w);
            }
        }
        cout << dp[m] << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    电脑硬件——硬盘
    【JS】牛客专项练习02
    2022 最全 Java 面试手册终于开源了,包含了 29 个知识点
    零代码编程:用ChatGPT批量提取flash动画swf文件中的mp3
    紧急避坑!美团一面就凉透?Java+数据库+Linux+缓存+算法+Redis+网络等等看不透的请看这篇!
    恢复grub在硬盘对多系统的引导
    springboot原理篇-bean管理
    力扣labuladong——一刷day38
    假设二叉树采用二叉链表存储结构,设计一个用非递归的算法求二叉树高度
    Nodejs安装及常见问题
  • 原文地址:https://blog.csdn.net/u012124438/article/details/127916768