数据结构与算法——0-1背包问题



第一种方法:

我们从第一个物品开始选择,此时背包的剩余空间为weight;

然后选择第二个物品,此时有两种情况,一是将该物品装入背包里,二是不将该物品装入背包里;

ret = max(package_0_1(num + 1, things, weight - things[num].first) + things[num].second, package_0_1(num + 1, things, weight));

。。。。直到将选择完最后一个物品;
这种方法的搜索深度是n,每一层的搜索都需要两个分支,最坏就是需要O(2^n);

第二种方法:

第一种方法有一个重复判断问题;
递归调用函数的时候会重复执行相同的情况,所以我们采取一种方法来规避这种重复操作;
用一个二维数组记录递归函数执行的每一种情况,总共有n*m中情况,所以最多执行n*m次递归函数;时间复杂度变为O(n*m);

ret = max(package_0_1_advanced(num + 1, things, weight - things[num].first) + things[num].second, package_0_1_advanced(num + 1, things, weight));

第一种方法:

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>//pair, make_pair
using namespace std;

/*********************************************************************
参数num表示当前第num个物品
参数weight表示当前背包剩下的容量
things中的成员的first表示物品的质量,second表示物品的价值
*********************************************************************/
int package_0_1(int num, vector<pair<int, int> > & things, int weight)
{
	int ret;
	if (num == things.size()){
		ret = 0;
	}
	else if (weight < things[num].first){//当前背包剩下的空间weight不能装入第num个物品,所以继续选择下一个物品
		ret = package_0_1(num + 1, things, weight);
	}
	else{//当前背包剩下的空间weight可以装入第num个物品,但是我们有两个选择可以装入和不装入,返回比较大的那个情况,返回的价值的大小
		ret = max(package_0_1(num + 1, things, weight - things[num].first) + things[num].second, package_0_1(num + 1, things, weight));
		//package_0_1(num + 1, things, weight - things[num].first) + things[num].second是选择装入第num个物品
	}
	return ret;
}


void input_data(int *number, vector<pair<int, int> > & things, int * total_weight)
{
	cout << "Input the number of things: ";
	cin >> *number;
	cout << "Input the things' weight and value:\n";
	int weight, value;
	for (int i = 0; i < *number; ++i){
		cin >> weight;
		cin.get();
		cin >> value;
		cin.get();
		things.push_back(make_pair(weight, value));
	}
	cout << "Input total weight: ";
	cin >> *total_weight;
}

int main()
{
	int total_weight;//背包总的容量
	int number;//物品的个数
	vector<pair<int, int> > things;//pair<int, int> 表示物品的质量和价值的组合

	input_data(&number, things, &total_weight);

/*  //仅仅是为了测试输入的数据对不对
	cout << "Output the things: ";
	for (int i = 0; i < things.size(); ++i){
		cout << things[i].first << "," << things[i].second << "  ";
	}
	cout << endl;
*/

	int max_value = package_0_1(0, things, total_weight);//背包可以装入的物品的最大价值
	cout << "max value is " << max_value << endl;

	system("pause");
	return 0;
}


第二种方法:

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>//pair, make_pair
using namespace std;

#define MAXNUMBER 100
#define MAXWEIGHT 10000
int book[MAXNUMBER][MAXWEIGHT];//记忆数组

/*********************************************************************
参数num表示当前第num个物品
参数weight表示当前背包剩下的容量
things中的成员的first表示物品的质量,second表示物品的价值
*********************************************************************/
int package_0_1_advanced(int num, vector<pair<int, int> > & things, int weight)
{
	if (book[num][weight] >= 0){//如果此时判断它的值大于等于0,则表示已经判断过这种情况,直接返回;
		return book[num][weight];
	}
	int ret;
	if (num == things.size()){
		ret = 0;
	}
	else if (weight < things[num].first){//当前背包剩下的空间weight不能装入第num个物品,所以继续选择下一个物品
		ret = package_0_1_advanced(num + 1, things, weight);
	}
	else{//当前背包剩下的空间weight可以装入第num个物品,但是我们有两个选择可以装入和不装入,返回比较大的那个情况,返回的价值的大小
		ret = max(package_0_1_advanced(num + 1, things, weight - things[num].first) + things[num].second, package_0_1_advanced(num + 1, things, weight));
		//package_0_1(num + 1, things, weight - things[num].first) + things[num].second是选择装入第num个物品
	}
	book[num][weight] = ret;
	return ret;
}
void input_data(int *number, vector<pair<int, int> > & things, int * total_weight)
{
	cout << "Input the number of things: ";
	cin >> *number;
	cout << "Input the things' weight and value:\n";
	int weight, value;
	for (int i = 0; i < *number; ++i){
		cin >> weight;
		cin.get();
		cin >> value;
		cin.get();
		things.push_back(make_pair(weight, value));
	}
	cout << "Input total weight: ";
	cin >> *total_weight;
	
	//初始化标志数组book, 比如book[i][j]的值记录的是第i个商品,背包剩下容量j的时候背包包含的价值;
	//如果此时判断它的值大于等于0,则表示已经判断过这种情况,直接返回;
	//如果此时判断它的值还是小于0,则表示还没有判断过这种情况;
	memset(book, -1, sizeof(book));//将该数组的初值置为-1
}

int main()
{
	int total_weight;//背包总的容量
	int number;//物品的个数
	vector<pair<int, int> > things;//pair<int, int> 表示物品的质量和价值的组合

	input_data(&number, things, &total_weight);

/*  //仅仅是为了测试输入的数据对不对
	cout << "Output the things: ";
	for (int i = 0; i < things.size(); ++i){
		cout << things[i].first << "," << things[i].second << "  ";
	}
	cout << endl;
*/

	int max_value = package_0_1_advanced(0, things, total_weight);//背包可以装入的物品的最大价值
	cout << "max value is " << max_value << endl;

	system("pause");
	return 0;
}


比较好的参考链接:

http://www.cnblogs.com/daoluanxiaozi/archive/2012/05/06/2486105.html

http://shmilyaw-hotmail-com.iteye.com/blog/2009761

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值