算法1
使用常规的01背包做法,按照以下的代码1,实际上是不用物品i和用物品i的比较,即第一个for循环f[i-1][j-v[i]] + w[i]和f[i-1][j]的比较。f[i-1][j-v[i]] + w[i]比较大的话,就用物品i,f[i-1][j]比较大的话,就不用物品i。
这样子在最后一轮的时候,是在比较是否使用了物品n;
所以从最后一轮往前面推,先判断是否使用了物品n,看代码1的第二个for循环,i=n,j=m; f[i][m] == f[i-1][m-v[i]] + w[i]的话,就表明使用了物品n;再继续迭代,判断是否使用了物品n-1, 通过第二个i循环就可以求出来是否使用了物品n, n-1,n-2…
但是这两个for循环的i,是判断是否使用了物品n, n-1,n-2…题目要求按照字典序,是从物品1到n。
把这两个for循环的i的增长顺序倒过来(i从1到N改成,从N到1),即可满足题意,判断是否使用了物品1, 2, …n。
代码1
//第一个for循环
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= V; j++) {
f[i][j] = f[i - 1][j];//不用物品i
if (j >= v[i])
f[i][j] = max(f[i][j], f[i-1][j-v[i]] + w[i]);
//f[i-1][j-v[i] + w[i]表示用物品i
}
}
//第二个for循环
for(int i=n; i>=1; i--) {
if (m>=v[i] && f[i][m] == f[i-1][m-v[i]] + w[i]) {
cout<< i << ' ';
m-=v[i];
}
}
C++ 代码
#include <iostream>
using namespace std;
const int si = 1010;
int v[si], w[si], f[si][si];
int main() {
int n, m;
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 = 1; 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]);
}
}
for(int i=1; i<=n; i++) {
if (m>=v[i] && f[i][m] == f[i+1][m-v[i]] + w[i]) {
cout<< i << ' ';
m-=v[i];
}
}
return 0;
}