有
N
N
N 件物品和一个容量是
V
V
V 的背包。每件物品只能使用一次。
第
i
i
i 件物品的体积是
v
i
v_i
vi,价值是
w
i
w_i
wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出 最优选法的方案数。注意答案可能很大,请输出答案模
1
0
9
+
7
10^9+7
109+7 的结果。
输入格式
第一行两个整数,
N
,
V
N,V
N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有
N
N
N 行,每行两个整数
v
i
,
w
i
v_i,w_i
vi,wi,用空格隔开,分别表示第
i
i
i 件物品的体积和价值。
输出格式
输出一个整数,表示 方案数 模
1
0
9
+
7
10^9+7
109+7 的结果。
数据范围
0
<
N
,
V
≤
1000
0<N,V≤1000
0<N,V≤1000
0 < v i , w i ≤ 1000 0<v_i,w_i≤1000 0<vi,wi≤1000
输入样例:
4 5
1 2
2 4
3 4
4 6
输出样例:
2
首先这个要求的是体积不超过 V V V 并且总价值最大的 方案数, 首先需要求出的就是总价值最大, 其次是方案数, 然后要让方案数 对应上总价值, 不同的体积对应不同的方案数, 所以方案数的状态要用体积恰好为 j j j 来表示, 而不能用不超过 j j j 来表示,然后因为方案数要与总价值相对应,所以总价值的状态也要用 体积恰好为 j j j 来表示.
状态表示
f
[
i
]
[
j
]
f[i][j]
f[i][j] : 在前
i
i
i 个物品中选,并且体积恰好为
j
j
j 的集合
状态属性: 总价值的最大值
状态计算: 选第
i
i
i 个物品 和 不选第
i
i
i 个物品
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
j
]
,
f
[
i
−
1
]
[
j
−
v
[
i
]
]
+
w
[
i
]
)
;
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
f[i][j]=max(f[i−1][j],f[i−1][j−v[i]]+w[i]);
状态表示
c
n
t
[
i
]
[
j
]
cnt[i][j]
cnt[i][j] : 在前
i
i
i 个物品中选, 并且总体积恰好为
j
j
j 的集合
状态属性: 体积j对应的方案数
令
r
e
s
res
res 表示体积为
j
j
j 时的方案数
如果
m
a
x
=
=
f
[
i
]
[
j
]
max == f[i][j]
max==f[i][j]
---->
r
e
s
+
=
c
n
t
[
i
]
[
j
]
;
res += cnt[i][j];
res+=cnt[i][j];
如果
m
a
x
=
=
f
[
i
]
[
j
−
v
]
max == f[i][j - v]
max==f[i][j−v]
----->
r
e
s
+
=
c
n
t
[
i
]
[
j
−
v
]
;
res += cnt[i][j - v];
res+=cnt[i][j−v];
最后更新
c
n
t
[
i
]
[
j
]
cnt[i][j]
cnt[i][j]
------->
c
n
t
[
i
]
[
j
]
=
r
e
s
cnt[i][j] = res
cnt[i][j]=res %
m
o
d
;
mod;
mod;
#include<iostream>
#include<algorithm>
#include<cstring>
const int N = 1100, mod = 1e9 + 7;
int f[N], cnt[N], n, m;
using namespace std;
int main()
{
cin >> n >> m;
memset(f, - 0x3f, sizeof f); //因为这里是恰好体积为j,且求最大价值,所以需要初始化为负无穷
f[0] = 0; //当体积为0时, 价值初始化为0
cnt[0] = 1; // 当体积为0时, 即什么也不选时,也是一种方案
for(int i = 1; i <= n; i ++ )
{
int v, w;
cin >> v >> w;
int maxv = 0;
for(int j = m; j >= v; j -- ) //枚举体积
{
maxv = max(f[j], f[j - v] + w); //状态转移
int res = 0; //创建变量保存当前的方案数
if(maxv == f[j]) res += cnt[j]; //状态转移
if(maxv == f[j - v] + w) res += cnt[j - v]; //状态转移
cnt[j] = res % mod; //更新状态
f[j] = maxv; //更新状态
}
}
int res = 0;
for(int i = 0; i <= m; i ++ ) res = max(res, f[i]); //枚举体积,找到最大价值
int ans = 0;
//如果当前价值等于最大价值, 记录方案数
for(int i = 0; i <= m; i ++ ) if(res == f[i]) ans = ( ans + cnt[i] ) % mod;
cout << ans << '\n';
}