题面
题解
- 01背包问题求具体方案数,题目要求所选方案的字典序最小,我们看从1到n的物品中只有3中情况,只能选,则必须选;不能选,则必不选;可选可不选,则必须选,因为从前向后,前面选择的一定比后面的选择好
- 我们可以从后向前,求出当前背包的最大总价值就是 f[1][m]
- 再从第1个物品遍历到第n个物品,其中f[i][j]为当前最优情况,若满足
(1) f [ i ] [ j ] == f [ i + 1 ] [ j ] , 则表示f[ i ] [ j ] 是从f [ i + 1 ] [ j ] 状态转移过来的
(2) f [ i ] [ j ] == f [ i + 1 ] [ j - v [ i ] ] + w [ i ] , 则表示f [ i ] [ j ] 是从 f [ i + 1][j - v[i]]状态转移过来的
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int w[N], v[N];
int f[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
for (int i = n; i >= 1; i--) {
//每个状态是从它后边更新过来的
for (int j = 0; j <= m; j++) {
f[i][j] = f[i + 1][j];
if (j >= v[i]) {
f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);
}
}
}
int j = m; // f[1][m]是最大值
for (int i = 1; i <= n; i++) {
if (j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]) {
cout << i << " ";
j -= v[i];
}
}
cout << endl;
return 0;
}