0-1揹包問題---動態規劃

一、問題描述


   0-1揹包問題可描述爲:n個物體和一個揹包。對物體i,其價值爲value,重量爲weight,揹包的容量爲W。如何選取物品裝入揹包,使揹包中所裝入的物品總價值最大?



二、算法設計



  2.1設計算法所需的數據結構。採用結構體Goods來存放單個貨物信息,揹包容量爲nKnapSackCap,自定義數據類型vector<vector<int>>用來存放每一次迭代的執行結果,用數組knapStackGoods存放最終裝入揹包的物品。


   2.2初始化。(由於vector類功能的限制,這裏爲了方便將record所有元素設置爲0)


   2.3按照下式遞推record,確定前i個物品能夠裝入揹包的最優值。


  


    2.4求解最優值,結果存入數組knapStackGoods中。


三、算法描述

//問題求解
void KnapSack_0_1(AllGoods &allGoods,int knapSackCap,AllGoods &knapStackGoods)
{
	RecordTable record;//定義記錄表
	
	vector<int> temp;//一個臨時變量,用來初始化record

	//將record所有元素初始化爲0
	for(int i = 0;i <= allGoods.size();++i)
	{
		record.push_back(temp) ;
		for(int j = 0;j <=knapSackCap;++j)
		{
			record[i].push_back(0);
		}
	}

	//計算record[i][j]
	for(int i = 1;i <= allGoods.size();++i)
	{
		for(int j = 1;j <=knapSackCap;++j)
		{
			if(j < allGoods[i - 1].weight)
			{
				record[i][j] = record[i - 1][j];
			}
			else
			{
				if(record[i - 1][j - allGoods[i - 1].weight] + allGoods[i -1].value < record[i - 1][j] )
				{
					record[i][j] = record[i - 1][j];
				}
				else
				{
					record[i][j] = record[i - 1][j - allGoods[i - 1].weight] + allGoods[i - 1].value ;
				}
			}
		}
	}

	//構造最優解
	int j = knapSackCap;
	for(int i = allGoods.size();i > 0;--i)
	{
		if(record[i][j] > record[i - 1][j])
		{
			knapStackGoods.push_back(allGoods[i - 1]);
			j -= allGoods[i - 1].weight;
		}
	}
}


四、算法複雜性分析


算法中有兩層嵌套for循環,爲此可選定語句j < allGoods[i - 1].weight爲基本語句,其運行時間爲nKnapStackCap * nGoodsNum;則算法時間複雜性爲O(nKnapStackCap * nGoodsNum)。又因爲用到輔助變量record,所以其空間複雜性爲O(nKnapStackCap * nGoodsNum)。


五、實現代碼


#include <iostream>
#include <vector>



using namespace std;

const int nGoodsNum = 5;
const int nKnapSackCap = 10;


class Goods //定義貨物數據類型
{
public:
	int weight;
	int value;
};

typedef vector<Goods> AllGoods;//定義所有貨物數據類型
typedef vector<vector<int>> RecordTable;//定義記錄表數據類型

//問題求解
void KnapSack_0_1(AllGoods &allGoods,int knapSackCap,AllGoods &knapStackGoods)
{
	RecordTable record;//定義記錄表
	
	vector<int> temp;//一個臨時變量,用來初始化record

	//將record所有元素初始化爲0
	for(int i = 0;i <= allGoods.size();++i)
	{
		record.push_back(temp) ;
		for(int j = 0;j <=knapSackCap;++j)
		{
			record[i].push_back(0);
		}
	}

	//計算record[i][j]
	for(int i = 1;i <= allGoods.size();++i)
	{
		for(int j = 1;j <=knapSackCap;++j)
		{
			if(j < allGoods[i - 1].weight)
			{
				record[i][j] = record[i - 1][j];
			}
			else
			{
				if(record[i - 1][j - allGoods[i - 1].weight] + allGoods[i -1].value < record[i - 1][j] )
				{
					record[i][j] = record[i - 1][j];
				}
				else
				{
					record[i][j] = record[i - 1][j - allGoods[i - 1].weight] + allGoods[i - 1].value ;
				}
			}
		}
	}

	//構造最優解
	int j = knapSackCap;
	for(int i = allGoods.size();i > 0;--i)
	{
		if(record[i][j] > record[i - 1][j])
		{
			knapStackGoods.push_back(allGoods[i - 1]);
			j -= allGoods[i - 1].weight;
		}
	}
}

//獲取物品信息,此處只是將書上例子輸入allGoods
void GetAllGoods(AllGoods &allGoods)
{
	Goods goods;

	goods.weight = 2;
	goods.value    = 6;
	allGoods.push_back(goods);


	goods.weight = 2;
	goods.value    = 3;
	allGoods.push_back(goods);

	goods.weight = 6;
	goods.value    = 5;
	allGoods.push_back(goods);

	goods.weight = 5;
	goods.value    = 4;
	allGoods.push_back(goods);

	goods.weight = 4;
	goods.value    = 6;
	allGoods.push_back(goods);
}
int main()
{
	AllGoods allGoods;
	AllGoods knapStackGoods;
	GetAllGoods(allGoods); //要求同樣重量的物品,價值大的排在前面

	//求解
	KnapSack_0_1(allGoods,nKnapSackCap,knapStackGoods);


	//輸出結果
	cout<<"物品個數:"<<nGoodsNum<<endl;
	for(int i = 0 ;i < allGoods.size(); ++i)
	{
		cout<<"重量:"<<allGoods[i].weight<<"   價值: "<<allGoods[i].value<<endl;
	}

	cout<<"揹包容量: "<<nKnapSackCap<<endl;
	cout<<"揹包中可裝入物品:"<<endl;

	for(int i = 0;i < knapStackGoods.size();++i)
	{
		cout<<"重量:"<<knapStackGoods[i].weight<<"   價值: "<<knapStackGoods[i].value<<endl;
	}
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章