AcWing 12. 背包问题求具体方案
原题链接
中等
作者:
ITNXD
,
2021-04-25 20:57:53
,
所有人可见
,
阅读 307
详细请查看注释
参考代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
/*
01背包 + 记录路径
状态表示:f[i][j]从前i个物品中选,总体积不超过j的选法集合的总体积最大值
状态计算:
选 i:f[i - 1][j - v[i]] + w[i]
不选i:f[i - 1][j]
最终答案:f[n][m]
路径记录:记录转移状态即可! ---> f[i] 是由 f[i - 1]转移过来的!
由于要保证字典序,即能选i - 1就不选i,若从f[n][m]往前推的话,无法保证能选i - 1就不选i!
解决方法:状态从后向前计算即可,则最终答案为f[1][m](表示从后i个物品中选体积不超过m即可)!
因此:若选i集合最优:则优先选i
若不选i集合最优:则必然不能选i
若选i集合和不选i集合都可取最优值:则优先选i
*/
int n, m, f[N][N], v[N], w[N], pre[N];
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i];
// 倒序DP
for(int i = n; i > 0; i --)
for(int j = 0; j <= m; j ++){
f[i][j] = f[i + 1][j];
if(j - v[i] >= 0) f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);
}
// 最终答案就是f[1][m]
int i = 1, j = m;
while(i <= n){
// 优先取选i的集合即可保证字典序!
if(j >= v[i] && f[i + 1][j] <= f[i + 1][j - v[i]] + w[i]){
cout << i << " ";
j -= v[i];
}
// 可选或不可选i都要后移
i ++;
}
return 0;
}