蛮力法解决0/1背包问题

时间:2020-12-30 04:23:58

    使用蛮力法解决0/1背包问题,就是将所有的物品装入背包的可能全部列举出来。这个可以通过递归的方式实现。递归的过程可以看成是对一棵树的深度优先遍历:

蛮力法解决0/1背包问题

例如上图,假设从背包中的1号物品开始列举所有的可能。如果每一层仅仅简单的在循环中使用递归,则该程序就不会结束。需要使用一个一维向量用于标记当前哪些编号已经装入了。

例如,当前1号物品已经装入背包,首先标记1号物品已经装入。之后,在循环中首先选择2号物品,如果没有超出背包的最大承重的话,标记2号物品已经装入。当前还有3、4号物品没有装入,所以继续递归尝试装入3、4号物品。在装入2号物品之后的所有可能的递归全部完成后,修改当前标记,并将2号物品从背包中拿出,之后就可以递归遍历放入3号物品之后的可能的情况了。

代码如下:

#include <iostream>
#include <vector>
#define PAC_MAX_VOL	10	//背包最大承重10

using namespace std;

void dfs(const vector<int> weights, const vector<int> vals, bool visit[], int currWeight, vector<int> seq);
void outputResult(vector<int> weights, vector<int> vals, bool visit[], int currWeight, vector<int> seq);

/**
*	使用递归的方式遍历所有的可能
*/
void dfs(const vector<int> weights, const vector<int> vals, bool visit[], int currWeight, vector<int> seq) {
	for (int i = 0; i < 4; ++i) {
		if (!visit[i]) {
			if (currWeight + weights[i] > PAC_MAX_VOL)
				continue;
			visit[i] = true;
			seq.push_back(i);		//将当前步加入到序列中
			dfs(weights, vals, visit, (currWeight + weights[i]), seq);		//基于当前状态深度遍历
			seq.erase(find(seq.begin(), seq.end(), i));		//从序列中删除
			visit[i] = false;
		}
	}
	outputResult(weights, vals, visit, currWeight, seq);
	return;
}

/**
*	输出当前结果
*/
void outputResult(vector<int> weights, vector<int> vals, bool visit[], int currWeight,vector<int> seq) {
	cout << "当前背包的重量是:" << currWeight << ", ";
	int sumVal = 0;
	for (int i = 0; i < 4; ++i)
		if (visit[i])
			sumVal += vals[i];
	cout << "当前背包的总价值为:" << sumVal << endl;
	cout << "当前结果集(编号)是:";
	for (auto ele : seq) {
		cout << ele << "  ";
	}
	cout << "\n-----------------------------" << endl;	
}

int main()
{
	const vector<int> weights = { 7,3,4,5 };		//各个物品的重量
	const vector<int> vals = { 42,12,40,25 };		//各个物品的价值
	vector<int> seq;
	bool visit[4] = {false};			//用于在递归中表示当前已有哪些物品放在背包中了
	dfs(weights, vals, visit, 0, seq);
    return 0;
}

运行结果如下:

蛮力法解决0/1背包问题