資料結構與演算法——0-1揹包問題

readyao發表於2015-12-26



第一種方法:

我們從第一個物品開始選擇,此時揹包的剩餘空間為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

相關文章