• AcWing 11. 背包问题求方案数


    题目传送门

    一、分析过程

    本题是 背包DP 中的经典题型 —— 【背包DP求最优方案总数

    \(01\)背包的转移方程\(f[i,j] = max(f[i - 1,j],f[i - 1,j - v] + w)\)

    其中\(g[i,j]\)\(f[i,j]\)取最大值的方案数

    \(f[i,j]\)是从\(f[i - 1,j]\)转移过来的,则\(g[i,j] = g[i - 1,j]\)

    \(f[i,j]\)是从\(f[i - 1,j - v] + w\)转移过来的,则\(g[i,j] = g[i - 1,j - v]\)

    \(f[i,j]\)均能从\(f[i - 1,j]\)\(f[i - 1,j - v] + w\)转移过来的,则\(g[i,j] = g[i - 1,j] + g[i - 1,j - v]\)

    将所有的最大值所对应的方案数累加在一起,即为方案数总和

    二、二维实现

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 1010;
    const int MOD = 1e9 + 7;
    
    int n, m;
    int w[N], v[N];
    int f[N][N], g[N][N];
    
    int main() {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
        //01背包求最大价值
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= m; j++) {//二维是正序遍历
                f[i][j] = f[i - 1][j];
                if (j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
            }
        //前0个物品中选,体积是0的情况下,最大价值就是0,一种方案
        g[0][0] = 1;
    
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                //查看一下当前的最大值,从前面哪个状态转移而来
                if (f[i][j] == f[i - 1][j])
                    g[i][j] = (g[i][j] + g[i - 1][j]) % MOD;//叠加方案数
    
                if (j >= v[i] && f[i][j] == f[i - 1][j - v[i]] + w[i])
                    g[i][j] = (g[i][j] + g[i - 1][j - v[i]]) % MOD;
            }
        }
        int res = 0;
        for (int i = 1; i <= m; i++)//遍历每一个体积
            if (f[n][i] == f[n][m]) res = (res + g[n][i]) % MOD;
    
        cout << res << endl;
        return 0;
    }
    
    

    三、一维实现

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1010;
    const int MOD = 1e9 + 7;
    
    int f[N];   //f[i]用来存储背包容积为i时的最大价值,
    int g[N];   //g[i]用来存储背包容积为i时,获取到最大价值时的方案数
    
    int main() {
        //优化输入
        ios::sync_with_stdio(false);
        int n, m;
        cin >> n >> m;
        //先初始化所有的 g[i]为 1,因为背包里什么也不装也是一种方案,方案数最小是1
        for (int i = 0; i <= m; i++) g[i] = 1;
    
        for (int i = 1; i <= n; i++) {
            int v, w;
            cin >> v >> w;
            for (int j = m; j >= v; j--) {
                //求出装新物品时的总价值,与不装新物品时作对比
                int value = f[j - v] + w;
                //如果装新物品的总价值更大,那么用f[j−v]+w来更新f[j](经典01背包)
                if (value > f[j]) {
                    f[j] = value;
                    //用g[j−v]更新g[j]
                    g[j] = g[j - v];
                } else if (value == f[j])
                    //如果总价值相等,那么最大价值的方案数就多了 g[j−v]种
                    g[j] = (g[j] + g[j - v]) % MOD;
            }
        }
        printf("%d", g[m]);
        return 0;
    }
    
    
  • 相关阅读:
    python机器学习:推荐系统实现(以矩阵分解来协同过滤)
    使用SAS,Stata,HLM,R,SPSS和Mplus的分层线性模型HLM
    R语言中小样本违反异方差性的线性回归
    R语言基于协方差的结构方程拟合的卡方检验
    R语言异方差回归模型建模:用误差方差解释异方差
    R语言中的生存分析Survival analysis晚期肺癌患者4例
    python列表的方法(改变原列表)
    python修改列表
    python列表的 + 、* 、in 、 not in 、 len() 、 max() 、 min()
    python切片(获取一个子列表(数组))
  • 原文地址:https://www.cnblogs.com/littlehb/p/15727174.html
Copyright © 2020-2023  润新知