题目描述
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例
2
AC Code
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 1005;
const ll MOD = 1000000007;
int a[maxn] = {0},b[maxn] = {0},f[maxn] = {0},g[maxn] = {0};
int n,v,ans = 0,MAX = 0;
void init(){
g[0] = 1;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
}
int main()
{
cin>>n>>v;
init();
for(int i=1;i<=n;i++){
for(int j=v;j>=a[i];j--){
int tmp = max(f[j],f[j-a[i]]+b[i]);
int s = 0;
if(tmp == f[j]){
s += g[j];
}
if(tmp == f[j-a[i]]+b[i]){
s += g[j-a[i]];
}
f[j] = tmp;
g[j] = s%MOD;
MAX = max(MAX,tmp);
}
}
for(int i=1;i<=v;i++){
if(f[i] == MAX){
ans = (ans + g[i])%MOD;
}
}
cout<<ans;
return 0;
}
解释
〇本题思路来源:背包问题求方案数。
①很明显的01背包问题,但是要求的不是能装入背包的最大价值,而是要求能以多少种方式将物品装入背包后得到最大价值。因此,需要两个dp数组,一个数组为f,用于存储最大价值,一个数组为g,用于存储最大价值下最多能装入的方案数。
②dp部分:
for(int i=1;i<=n;i++){
for(int j=v;j>=a[i];j--){//仍然像01背包那样枚举每一块空间。
int tmp = max(f[j],f[j-a[i]]+b[i]);//将这一步可以得到的可能最大价值存储在tmp中,
//来寻找会不会有相同的最大价值存在于装入不同内容的背包处。
int s = 0;
if(tmp == f[j]){//等于自身时自增
s += g[j];
}
if(tmp == f[j-a[i]]+b[i]){//向前寻找
s += g[j-a[i]];
}
f[j] = tmp;
g[j] = s%MOD;
MAX = max(MAX,tmp);
}
}