【c++回顾】3.1经典算法问题-0/1背包填满问题

简单的背包填满问题:(题目参考这个网站)
假设有一个能装入容量为C的背包和n件重量分别为w1,w2,…,wn的物品,能否从n件物品中挑选若干件恰好装满背包,要求找出所有满足上述条件的解。
示例答案:当C=10,各件物品重量为{1,8,4,3,5,2}时,可以找到下列4组解:(1,4,3,2)、(1,4,5)、(8,2)和(3,5,2)。

上述网站给出了一种解法,我这里给出另一种解法。我的解题思路:
每个物品只有两种可能,拿或不拿,n个物品共有2的n次方种可能,遍历所有可能就可以求出所有满足条件的解。
问题转换为:一个n维数组,数组的每个元素为1或0,如何快速遍历这个数组的所有取值情况。
核心递归算法:

//递归实现n维0/1数组的取值情况遍历
//使用时vec初始化为全零数组,i初始化为0,递归前先进行一次operation
//递归时vec的第i个元素进行变化
void TraverseVector(vector vec, int i)
{
	//如果i超出vec范围,则返回
	if (i == vec.size())
		return;
	//递归
	TraverseVector(vec, i + 1);
	//变化第i个元素,进行操作
	vec[i] = 1;

	//operation
	/*以输出为例
	for (int o = 0; o < vec.size(); o++)
		cout << vec[o] << ' ';
	cout << endl;*/

	//递归
	TraverseVector(vec, i + 1);
}

更改上述算法中的operation部分即可解决我们的背包填满问题,完整代码如下:

//假设有一个能装入容量为C的背包和n件重量分别为w1,w2,,...,wn的物品,能否从n件物品中挑选若干件恰好装满背包,要求找出所有满足上述条件的解。
//当C=10,各件物品重量为{1,8,4,3,5,2}时,可以找到下列4组解:(1,4,3,2)、(1,4,5)、(8,2)和(3,5,2)。
//每个物品只有两种可能,拿或不拿,n个物品共有2的n次方种可能,遍历所有可能就可以求出所有满足条件的解
//问题转换为:一个n维数组,数组的每个元素为1或0,如何快速遍历这个数组的所有取值情况
#include "pch.h"
#include 
#include 
using namespace std;
//递归实现n维0/1数组的取值情况遍历
//使用时vec初始化为全零数组,i初始化为0,递归前先进行一次operation
//递归时vec的第i个元素进行变化
void TraverseVector(vector vec, int i)
{
	//如果i超出vec范围,则返回
	if (i == vec.size())
		return;
	//递归
	TraverseVector(vec, i + 1);
	//变化第i个元素,进行操作
	vec[i] = 1;

	//operation
	/*以输出为例
	for (int o = 0; o < vec.size(); o++)
		cout << vec[o] << ' ';
	cout << endl;*/

	//递归
	TraverseVector(vec, i + 1);
}

//给出拿取情况向量与重量列表向量,求解当前背包重量
int CalculateWeight(vector taken_items, vector weights)
{
	int weight = 0;
	for (int i = 0; i < taken_items.size(); i++)
		weight = weight + taken_items[i] * weights[i];
	return weight;
}
//根据拿取情况向量输出结果
void PrintResult(vector taken_items, vector weights)
{
	cout << "【求解结果】该组合满足条件";
	for (int i = 0; i < taken_items.size(); i++)
		if (taken_items[i])cout << weights[i] << ' ';
	cout << endl;
}
void BackpackProblem(vector vec, int i, int capacity, vector weights)
{
	//如果i超出vec范围,则返回
	if (i == vec.size())
		return;
	//递归
	BackpackProblem(vec, i + 1, capacity, weights);
	//变化第i个元素,进行操作
	vec[i] = 1;

	//operation
	//判断背包是否已满
	if (capacity == CalculateWeight(vec, weights))
		PrintResult(vec, weights);

	//递归
	BackpackProblem(vec, i + 1, capacity, weights);
}

int main()
{
	//初始化
	int capacity;
	vector weights;
	int number;
	cout << "输入背包容量及物品件数:" << endl;
	cin >> capacity >> number;
	cout << "输入这" << number << "个物品的重量" << endl;
	for (int i = 0; i < number; i++)
	{
		int weight;
		cin >> weight;
		weights.push_back(weight);
	}
	//定义拿取情况向量
	vector taken_items(number, 0);
	//定义遍历元素i
	int i = 0;
	//由于一个都不拿肯定不满足装满背包的条件,故无需操作当前向量,直接开始递归
	BackpackProblem(taken_items, i, capacity, weights);
	return 0;
}
/*
输入:
10 6
1 8 4 3 5 2
*/

运行结果:
【c++回顾】3.1经典算法问题-0/1背包填满问题_第1张图片

你可能感兴趣的:(c++回顾)