可以看成最短路问题
起点是(0 , 0),终点是(n , m) (这里(i,j)表示f[i][j]的最大值)
问题等价于求从(0,0)到(n,m)的最短路径的条数
用一个g[i][j]来记录到(i,j)的路径数
对于最短路问题,要求到一个点的最短路径,就要求判断一下从它通过哪个前一个节点到起点的距离最近,然后将该点的路径数加到所求点的路径数上;
同样的,对于该问题,观察其状态转移方程:f[i][j] = max(f[i - 1][j] , f[i - 1][j - v] + w),f[i][j]是从这两个点转移而来,哪个点大就选哪个,如果一样大,两个点的路径数都要加。
最后遍历一遍所有点,求出最大价值,然后将等于最大价值的方案数累加即可。
C++ 代码
#include <iostream>
using namespace std;
const int N = 1010 , mod = 1e9 + 7;
int v , w;
int f[N] , g[N];
int n , m;
int main()
{
cin >> n >> m;
g[0] = 1;
for(int i = 0 ; i < n ; i++)
{
cin >> v >> w;
for(int j = m ; j >= v ; j--)
{
int s = 0;
int maxv = max(f[j] , f[j - v] + w);
if(maxv == f[j]) s = g[j];
if(maxv == f[j - v] + w) s = (s + g[j - v]) % mod;
f[j] = maxv , g[j] = s;
}
}
int res = 0;
for(int i = 1 ; i <= m ; i++)
if(f[res] < f[i])
res = i;
int cnt = 0;
for(int i = 0 ; i <= m ; i++)
if(f[res] == f[i])
cnt = (cnt + g[i]) % mod;
cout << cnt << endl;
return 0;
}