問題的提出
背包問題(Knapsack problem)是一種組合優化的NP完全問題。
問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,
在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。
問題解決
本文介紹使用動態規划的方法解決此問題
算法思想:
- 1.將原問題分解為子問題:原問題為求解最大價值,分解為背包載重容量從1到最大量c分別能裝多少價值東西的 若干問題
- 2.確定狀態:使用 sum_value_matrix[n][c]保存,n表示前n個物件(number),c表達背包容量(capacity),所以這個變量意義為背包容量為c,前n個物件能裝入的最大價值
- 3.確定初始態值:當容量為1時,因為所有物品重量都大於1,所以sum_value_matrix[n][1]={0,0,0,0,0}
- 4.確定狀態轉移方程:sum_value_matrix[n][c]=max(sum_value_matrix[n-1][c], sum_value_matrix[n-1][c-w[n]]+v[n])
w[i]表示第i個物件的重量(weight),v[n]表示第一個物件的價值(value)
方程意義:
考慮第n件物品 放1 或者 不放0 時,
如果不放,那么其價值為前面 n-1 物品價值 sum_value_matrix[n-1][c]
如果放,那么其價值為前面 n-1 物品在容量為 c-w[n] 的時候的價值sum_value_matrix[n-1][c-w[n]],
加上第n件物品的價值 v[n](理由:滿足“最優化原理”)
代碼:
C++代碼
class PackageSolver {
public:
int sum_value_matrix[6][11];
int knapsack(PackageItem* items) {
init(items);
for (int c = 2; c <= 10; c++) {
for (int n = 2; n <= 5; n++) {
if (c < items[n].weight) {
//背包capacity 比第n項小
sum_value_matrix[n][c] = sum_value_matrix[n - 1][c];
}
else {
//裝得下第n項
//undo: c - items[n].weight>0? else?
int temp1 = sum_value_matrix[n - 1][c];
int temp2 = items[n].value;
if (c - items[n].weight > 0) {
temp2 = sum_value_matrix[n - 1][c - items[n].weight] + items[n].value;
}
sum_value_matrix[n][c] = temp1 > temp2 ? temp1 : temp2;
}
}
}
return sum_value_matrix[5][10];
}
//初始化
void init(PackageItem* items) {
//初始化0
for (int n = 1; n <= 5; n++) {
for (int c = 1; c <= 10; c++) {
sum_value_matrix[n][c] = 0;
}
}
//初始化第一列,第n件物品的weight value
for (int n = 1; n <= 5; n++) {
sum_value_matrix[n][1] = 0;
}
//初始化第一行,只裝第一個物品 容量為c時候的 總value
for (int c = 1; c <= 10; c++) {
if (c >= items[1].value) {
sum_value_matrix[1][c] = items[1].value;
}
//cout << sum_value_matrix[1][c];
}
}
void print() {
cout<<"x:capacity y:top n items"<<endl;
for (int n = 1; n <= 5; n++) {
for (int c = 1; c <= 10; c++) {
cout << sum_value_matrix[n][c] << ends;
}
cout << endl;
}
cout << endl;
}
};
背包項
struct PackageItem
{
string name;
int weight;
int value;
PackageItem(string name, int weight, int value) {
this->name = name;
this->weight = weight;
this->value = value;
}
void print() {
cout << "name:" << name << ends
<< "weight:" << weight << ends
<< "value:" << value << endl;
}
};
測試代碼
class Problem2Tester {
public:
//為了使得下標與實際意義一致,所以設置item[0]為空
struct PackageItem items[6] = {
{ " ", 0, 0 },
{ "a", 2, 2 },
{ "b", 2, 3 },
{ "c", 6, 5 },
{ "d", 5, 4 },
{ "e", 4, 6 },
};
PackageSolver ps;
void item_test() {
for (int i = 0; i <= 5; i++) {
items[i].print();
}
}
void init_test() {
ps.print();
ps.init(items);
ps.print();
}
void knapsack_test() {
ps.init(items);
ps.print();
ps.knapsack(items);
ps.print();
}
}tester2;
參考:
http://blog.csdn.net/mu399/article/details/7722810
http://blog.sina.com.cn/s/blog_6dcd26b301013810.html