AcWing 11. 背包问题求方案数


题目传送门

本题求\(01\)背包的最佳方案数,那么定义两个数组:\(f[N]\),\(g[N]\)

\(f[i]\)用来存储背包容积为 \(i\) 时的最佳方案的总价值,

\(g[i]\)为背包容积为 \(i\) 时总价值为最佳的方案数。

先初始化所有的 \(g[i]\)\(1\),因为背包里什么也不装也是一种方案。

外层循环 \(n\) 次,每次读入新物品的 \(v\),\(w\)

求出装新物品时的总价值,与不装新物品时作对比

如果装新物品的方案总价值更大,那么用 \(f[j?v]+w\) 来更新 \(f[j]\),用 \(g[j?v]\) 更新 \(g[j]\)

如果总价值相等,那么最大价值的方案数就多了 \(g[j?v]\) 种。

#include 

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;
}