zoukankan      html  css  js  c++  java
  • 动态规划 —— 背包问题总结

    背包问题

    1. 01背包
    2. 完全背包
    3. 多重背包
    4. 混合背包
    5. 二维费用的背包问题
    6. 分组背包
    7. 背包问题求方案数
    8. 求背包问题的方案
    9. 有依赖的背包问题

    一、01背包问题

    • 问题描述
      (N)件物品和一个容量是(V)的背包。每件物品只能使用一次。第(i)件物品的体积是(v_{i}),价值是(w_{i})。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。

    • 二维DP解法
      状态表示:(f[i][j]) 表示前(i)个物品,总体积是(j)的情况下,总价值最大时多少。(res = max{f[n][0],....,f[n][v]})
      状态计算:(f[i][j] = max left{ f[i-1][j],f[i-1][j-v_i] + v_i ight})。直接不选第(i)个物品或者在能选第i个物品的情况下,选择第(i)个物品。
      初始化:(f[0][0] = 0)
      复杂度分析: 状态数是(n^2,), 转移是(Oleft(1 ight)),每个状态数只需要进行常数次计算。总共的时间复杂度是(Oleft(n^2 ight)),即(NV)的。空间的复杂度也是(NV)

    • c++ 实现

    #include<iostream>
    using namespace std;
    
    const int N = 1010;
    
    int n,m; 
    int v[N],w[N]; // 体积、价值
    int dp[N][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 ++) {
                dp[i][j] = dp[i-1][j];
                if(j >= v[i]) dp[i][j] = max(dp[i][j],dp[i-1][j-v[i]] + w[i]);
            }
        }
        int res = 0;
        for(int i = 0; i <= m; i ++) res = max(res,dp[n][i]);
        cout << res << endl;
        return 0;
    }
    
    • 优化
      由于(f[i][j])只与(f[i-1][..]) 相关,所有可以使用滚动数组。但实际上不需要滚动数组,只需要一维数组也可以实现。
      (f[i])表示体积是(i)的情况下,最大价值是多少。

    • 错误示例:

    for(int i = 1; i <= n; i ++) {
          for(int j = 0; j <= m; j ++) {
                if(j >= v[i]) dp[j] = max(dp[j],dp[j-v[i]] + w[i]);
          }
    }
    

    上面的错误在dp[j] = max(dp[j],dp[j-v[i]] + w[i]) 这段代码。dp[j-v[i]]表示的是dp[i][j-v[i]]的状态而不是dp[i-1][j-v[i]]的状态。那么需要思考如何才能状态是正确的。解决方法是体积(j)从大到小枚举。

    • 优化后c++实现
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1010;
    int n,m;
    int v[N],w[N],dp[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 = m; j >= v[i]; j --) {
                dp[j] = max(dp[j],dp[j-v[i]]+w[i]);
            }
        }
        cout << dp[m] << endl;
        return 0;
        
    }
    

    不需要对(dp[j])进行遍历寻找(max),因为每一个(dp[j]都是由dp[j-v_i])转移而来,每一个(dp[j])保证的当前体积小于等于(j)下的最优,且(dp[j] >= dp[j-v_i]), 所以(dp[m]) 就是全局最优的答案。

    如果要求解体积恰好是m的情况下,最大价值是多少。初始化需要f[0] = 0, f[1~m] = -INF

    二、01背包问题

    三、完全背包问题

    四、多重背包问题

    五、混合背包问题

    六、01背包问题

    七、01背包问题

    八、01背包问题

  • 相关阅读:
    实现三联tab切换特效
    SQL Server对数据进行添加
    SmartUpload实现文件上传
    JavaScript图片轮播,举一反三
    SQL Server对数据进行删除
    用SQL Server查询所有数据并显示
    SQL Server日期格式化
    用SQL Server验证用户名和密码
    SQL Server存储过程作业(三)
    SQL Server存储过程作业(二)
  • 原文地址:https://www.cnblogs.com/Lysz1996/p/13909191.html
Copyright © 2011-2022 走看看