背包九讲之求具体的背包方案

827 阅读1分钟

具体题目描述可以见链接[www.acwing.com/problem/con…]. 本题要求输出具体的方案,由于最优背包的方案数可以是很多种,这题要求输出字典序最小的方案。

主要思路:要求解具体的方案首先的用2维矩阵去解背包,而不能用优化后的一维。因为要得到第i件物品是否放进背包中了,需要比较f[i][j]和f[i - 1][j]以及f[i - 1][j - w[i]] + v[i]的值,如果是前者表示第i件物品没有放入背包,如果是后者则是放进了背包,如果都相等则两种方案都会达到最优,这时候需要选出字典序最小的方案。为了选出字典序最小的方案,我们就不能从后往前选,而常规的解法使得只能从后往前选。要想使得可以从后往前选,那么可以在递推解背包的时候i从大到小去填写f[i][j]。

#include <iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

const int N = 1010;
int f[N][N];
int w[N];
int v[N];

int main()
{
	/*
	
	输入:
	4 5
	1 2
	2 4
	3 4
	4 6

	*/
	int n, m;
	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]);
			}
		}
	}
	int vol = m;
	for (int i = 1; i <= n; i++) {
		if (vol - w[i] >= 0 && f[i][vol] == f[i + 1][vol - w[i]] + v[i]) {
			cout << i << " ";
			vol -= w[i];
		}
	}
	cout << endl;
	//cout << f[1][m] << endl;
	system("pause");
}