<—点个赞吧QwQ
宣传一下算法提高课整理{:target=”_blank”}
有 $N$ 件物品和一个容量是 $V$ 的背包。每件物品只能使用一次。
第 $i$ 件物品的体积是 $v_i$,价值是 $w_i$。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 $1 … N$。
输入格式
第一行两个整数,$N,V$,用空格隔开,分别表示物品数量和背包容积。
接下来有 $N$ 行,每行两个整数 $v_i, w_i$,用空格隔开,分别表示第 $i$ 件物品的体积和价值。
输出格式
输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。
物品编号范围是 $1 … N$。
数据范围
$0 \\lt N, V \\le 1000$
$0\\lt v_i, w_i \\le 1000$
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例:
1 4
思路
这道题我们只需要把$0/1$背包问题的朴素代码加上求方案的过程即可。
为了方便写代码,我们要从后往前$\text{DP}$。(到后面就知道了)
由于我们是到这推$\text{DP}$的,所以我们要从前往后算方案。
从前往后枚举每一个数,如果选了一个物品,那么$\text{DP}$数组的地推式一定是成立的。所以我们一次美剧每一个物品,看看它是否满足递推式,如果满足,那这个物品就选了。
注意判断放不下的情况。
代码
#include <iostream>
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 >> w[i] >> v[i];
for (int i = n;i >= 1;i--) {
for (int j = 0;j <= m;j++) {
f[i][j] = f[i + 1][j];
if (j >= w[i]) f[i][j] = max (f[i][j],f[i + 1][j - w[i]] + v[i]);
}
}
for (int i = 1,j = m;i <= n;i++) {
if (j >= w[i] && f[i][j] == f[i + 1][j - w[i]] + v[i]) {
cout << i << ' ';
j -= w[i];
}
}
return 0;
}