通过分析01背包的状态转移
其实整个过程类似于找“最长路”
都是一步一步得转移过来
转移方程是$$f[j]=max(f[j],f[j-v]+w)$$
因此我们只需要知道每一次要选f[j]还是f[j-v]+w,或者两个都选,就可以知道是从哪个点连接到哪个点
我们用g[j]代表点1到点j共有多少个方案
计数dp我们一般初始化为f[0]=1(或者提前初始化为f[v[i]]=1也行,写成f[0]是为了偷懒)
g[]的转移方程是$$g[j]= (g[j]) || (g[j-v]) || (g[j]+g[j-v])$$
因为题目求的是最大价值,最大价值的状态不一定只有是体积为m的情况
因此在最后需要遍历一次体积,将与最大价值f[m]相同的方案也加入进来
#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
int f[1111],g[1111],n,m;
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
// memset(f,-0x3f,sizeof f);
// f[0]=0;
g[0]=1;
for(int i=1;i<=n;i++)
{
int v,w;
cin>>v>>w;
for(int j=m;j>=v;j--)
{
int maxn=max(f[j],f[j-v]+w);
int tmp=0;
if (maxn==f[j]) tmp+=g[j];
if (maxn==f[j-v]+w) tmp+=g[j-v];
g[j]=tmp%MOD;
f[j]=maxn;
}
}
int res=0;
for(int i=0;i<=m;i++) res=max(res,f[i]);
int cnt=0;
for(int i=0;i<=m;i++)
if (res==f[i])
cnt=(cnt+g[i])%MOD;
cout<<cnt;
return 0;
}