01背包
状态表示与01背包相同
集合分析与01背包完全相同
选择方案的判断,就是看每次方案的选择是哪一个
如果我们此时状态的计算f[i, j]的值是不选第i个物品的价值,即此时最大的价值就是f[i - 1, j],那么我们此时的方案就是不选第i个物品
同理,如果从右边取最大值,我们的答案就是选第i个
即我们判断这个值是等于哪一个来判断第i个物品选还是不选了
这样我们就可以从后往前推一遍来判断某个物品选还是不选了
为什么要从后往前推呢?
只有从后往前推才能逐一的判断从最优解的答案开始往前推
而答案还要保证字典序是最小的,那么我们在选取答案的时候要尽可能的拿到即选
而为了求到这个方案,那么我们上面推到那些就得全部颠倒,即从n到1开始转移,从1-n开始推出方案
#include <iostream>
using namespace std;
int n;
int m;
int f[1010][1010];
int w[1010];
int v[1010];
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> v[i] >> w[i];
}
for(int i = n; i; 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 i = 1, j = m;
while(i <= n){
if(j >= v[i] && f[i + 1][j - v[i]] + w[i] >= f[i + 1][j]){
cout << i << " ";
j -= v[i];
i++;
}
else{
i++;
}
}
return 0;
}