题目链接:
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出 最优选法的方案数。注意答案可能很大,请输出答案模 109+7 的结果。 输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。 输出格式 输出一个整数,表示 方案数 模 109+7 的结果。 数据范围 0<N,V≤1000 0<vi,wi≤1000 输入样例 4 5 1 2 2 4 3 4 4 6 输出样例: 2
解题思路:
f[i][j]: 从前 i 个物品中选择体积不超过 j 的最大价值
g[i][j]: 从前 i 个物品中选择体积不超过 j 且价值为最大价值的方案数。
接下来只要找出它的最大价值求出方案数即可:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 1010, mod = 1e9 + 7; int n, m; int v, w; int f[N], g[N]; int main() { cin >> n >> m; g[0] = 1; for (int i = 1; i <= n; i ++ ) { cin >> v >> w; for (int j = m; j >= v; j -- ) { int maxd = max(f[j], f[j - v] + w); // 找出最大价值 int s = 0; if (maxd == f[j]) s = g[j]; // 求方案数 if (maxd == f[j - v] + w) s = (s + g[j - v]) % mod; f[j] = maxd, g[j] = s; } } int res = 0; for (int i = 1; i <= m; i ++ ) // 找出最大价值的下标 if (f[i] > f[res]) res = i; int sum = 0; for (int i = 0; i <= m; i ++ ) // 计算最大价值的总方案数 if (f[res] == f[i]) sum = (sum + g[i]) % mod; cout << sum << endl; return 0; }