01背包求方案数
思路
c
n
t
[
i
]
[
j
]
cnt[i][j]
cnt[i][j] 表示 考虑第
i
i
i 个 物品,体积不超过
j
j
j 的最大价值的方案数
类似于最短路求方案数
c
n
t
[
i
]
[
j
]
=
c
n
t
[
i
+
1
]
[
j
−
v
[
i
]
]
cnt[i][j] = cnt[i+1][j-v[i]]
cnt[i][j]=cnt[i+1][j−v[i]] (
f
[
i
]
[
j
]
<
f
[
i
+
1
]
[
j
−
v
[
i
]
]
+
w
[
i
]
f[i][j] < f[i+1][j-v[i]]+w[i]
f[i][j]<f[i+1][j−v[i]]+w[i])
c
n
t
[
i
]
[
j
]
+
=
c
n
t
[
i
+
1
]
[
j
−
v
[
i
]
]
cnt[i][j] += cnt[i+1][j-v[i]]
cnt[i][j]+=cnt[i+1][j−v[i]] (
f
[
i
]
[
j
]
=
=
f
[
i
+
1
]
[
j
−
v
[
i
]
]
+
w
[
i
]
f[i][j] == f[i+1][j-v[i]]+w[i]
f[i][j]==f[i+1][j−v[i]]+w[i])
注意初始化
和计算答案
int n,m;
int f[1005][1005];
int cnt[1005][1005];
int v[1005],w[1005];
signed main()
{
cin>>n>>m;
forr(i,1,n) cin >> v[i] >> w[i];
//forr(i,0,m) cnt[n+1][i] = 1;
cnt[n+1][0] = 1;
for(int i = n;i;i--){
for(int j = 0; j <= m;j++){
f[i][j] = f[i+1][j];
cnt[i][j] = cnt[i+1][j];
if(j >= v[i]){
if(f[i][j] < f[i+1][j-v[i]]+w[i]){
f[i][j] = f[i+1][j-v[i]]+w[i];
cnt[i][j] = cnt[i+1][j-v[i]]; // 体积等于0 说明可以通过第i个转移 所以每个状态的 0位都要初始化为 1,作用是用来转移
}
else if(f[i][j] == f[i+1][j-v[i]]+w[i]){
(cnt[i][j] += cnt[i+1][j-v[i]]) %= mod;
}
}
cout << cnt[i][j] <<" ";
}
cout << endl;
}
int t = f[1][m];
int res = 0;
forr(i,0,m){
if(f[1][i] == t) (res += cnt[1][i])%=mod;
}
cout << res << endl;
return 0;
}
01背包求方案(字典序最小)
思路
物品逆序枚举方便正向输出答案
考虑
w
a
y
[
i
]
[
j
]
way[i][j]
way[i][j] 表示考虑第
i
i
i 个物品,体积不超过
j
j
j 的最大价值转移的物品下标
int f[1005][1005];
int way[1005][1005];
int w[1005],v[1005];
void print(int x,int y){
if(x == n+1) return ;
int k = way[x][y];
if(k) cout << k <<" ";
print(x+1,y-v[k]);
}
signed main()
{
cin>>n>>m;
forr(i,1,n){
cin>> v[i] >> w[i];
}
for(int i = n;i;i--){
for(int j = 1;j <= m;j++){
f[i][j] = f[i+1][j];
if(j >= v[i] && f[i][j] <= f[i+1][j-v[i]]+w[i]){
f[i][j] = f[i+1][j-v[i]]+w[i];
way[i][j] = i;
}
}
}
print(1,m);
return 0;
}