12. 背包问题求具体方案 - AcWing题库
分析
- 求具体方案实际上是判断每个物品是否被选
- 倒推出
f
[
n
]
[
m
]
f[n][m]
f[n][m] 是怎么求得的,和哪个状态相等,就代表了从哪个状态转移过来的
- 实际上,动态规划求方案对应了最短路问题求路径
- 字典序最小的处理:对于第一个物品,可能产生的三种情况,从前往后推
- 只能选
→
\to
→ 必选
- 只能不选
→
\to
→ 必定不选
- 可选可不选
→
\to
→ 一定选择第一个物品(这样保证了字典序最小)
- 在倒推状态转移路径的时候,只能在分叉转移的时候,即当前物品既可以选又可以不选 时,优先选,才能得到字典序最小。因此,我们本题求解时需要倒过来(从
N
N
N 递推到
1
1
1 ),然后再从
1
1
1 倒推回
N
N
N 找出路径
AcWing 1013. 机器分配【分组背包+背包DP输出方案—拓扑图分析】 - AcWing
Code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1050;
int f[N][N];
int vol[N], w[N];
int n, m;
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d%d", &vol[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 >= vol[i]) f[i][j] = max(f[i][j], f[i + 1][j - vol[i]] + w[i]);
}
}
int j = m;
for(int i = 1; i <= n; i++) {
if(j >= vol[i] && f[i][j] == f[i + 1][j - vol[i]] + w[i]) {
printf("%d ", i);
j -= vol[i];
}
}
return 0;
}