回溯法加剪枝解決01揹包問題 C

2021-08-14 08:11:35 字數 3701 閱讀 1098

01 揹包問題: knapsack 是解決如何將乙個揹包的價值最大劃的問題 

輸入:  c 揹包最大容量,w 物品的重量 ,v 物品的價值 

輸出:bestv 最大的可放置在揹包內的物品價值總和,bestx 對應bestp的物品取法,即最優值和最優解

例如:輸入:c = 30, w = v = , 

則輸出:bestv = 50, bestx =

不難看出,這個問題屬於npc問題,不存在多項式複雜度的解法,通常我們會用動態規劃(dynamic programming)解,此處我們用回溯法。回溯法本質上是深度優先搜尋(dfs)。我們可以把所有的解決離散問題的演算法都看做在答案的乙個子空間進行搜尋的過程。而在knapsack問題中,這個子空間既是高度為n(n為物品數量)的二叉樹,因為對於每個物品我們有兩種選擇,選或者不選。 

剪枝:剪枝的意思是在這個搜尋樹中,我們可以在進入某乙個節點之前大致估計一下可能的最好結果,如果最好結果沒有當前最好結果好,我們可以不進入這個節點,同時將該節點的子樹減掉。

執行結果:

剪枝

baoergutes-macbook-pro:desktop baoergute$ ./knapsack

list:

value 40 weight: 20 value per weight:2

value 25 weight: 15 value per weight:1.66667

value 25 weight: 15 value per weight:1.66667

after sorting:

value 40 weight: 20 value per weight:2

value 25 weight: 15 value per weight:1.66667

value 25 weight: 15 value per weight:1.66667

b:56.6667

b:40

b:50

b:25

b:25

best value is: 50

node count is: 7

item with value: 25 weight: 15

item with value: 25 weight: 15

未剪枝
baoergutes-macbook-pro:desktop baoergute$ ./knapsack_org

list:

value 40 weight: 20 value per weight:2

value 25 weight: 15 value per weight:1.66667

value 25 weight: 15 value per weight:1.66667

best value is: 50

node count is: 11

item with value: 25 weight: 15

item with value: 25 weight: 15

值得一提的是,剪枝並不改變演算法複雜度,理論上來講,在最壞情況下剪枝也不能提公升實際的執行速度

// 未剪枝版本

#include #include #include #include using namespace std;

int c = 30; //揹包容量

const int n = 3; //物件數目

int w = ; //物件重量陣列

int v = ; //物件收益陣列

int cw = 0; //當前揹包重量

int cv = 0; //當前揹包價值

double bestv = 0; //迄今最大的收益

int node_count = 0; //當前遍歷過的節點數

int bestx[n]; //迄今最佳選擇

int x[n]; //當前選擇

void getbest (int i, vector> l)

} return;

}// left child

if (cw + (l[i]).second <= c)

// right child

x[i] = 0;

getbest(i + 1, l);

}int main()

cout << "list:" << endl;

for (vector>::iterator itr = value_weight_list.begin(); itr != value_weight_list.end(); itr++)

cout << endl;

getbest(0, value_weight_list);

cout << "best value is: " << bestv << endl;

cout << "node count is: " << node_count << endl;

for (int i = 0; i < n; i++)

}cout << endl;

return 0;

}

// 剪枝版本

double bound(int i, vector> l)

// 拆分

if (i < n)

cout << "b:" << b << endl;

return b;

}

void getbest (int i, vector> l)

} return;

}// left child

if (cw + (l[i]).second <= c)

// 判斷剪枝

if (bound(i+1, l) > bestv)

}// 自定義比較運算子

bool mycomparator_dsc (paira, pairb)

int main()

cout << "list:" << endl;

for (vector>::iterator itr = value_weight_list.begin(); itr != value_weight_list.end(); itr++)

cout << endl;

// sort the list

// 此處我們用了自定義的運算子,按照價效比降序排列

sort(value_weight_list.begin(), value_weight_list.end(), mycomparator_dsc);

// print the sorted list

cout << "after sorting:" << endl;

for (vector>::iterator itr = value_weight_list.begin(); itr != value_weight_list.end(); itr++)

cout << endl;

getbest(0, value_weight_list);

cout << "best value is: " << bestv << endl;

cout << "node count is: " << node_count << endl;

for (int i = 0; i < n; i++)

}cout << endl;

return 0;

}

回溯法解決0 1揹包問題(c )

用回溯法解決0 1揹包問題時,其解空間有長度為n的0 1向量組成,並可以組織成高度為n 1滿二叉樹。二叉樹的結點按層次遍歷的順序從上到下 從左到右的順序編號 從1開始 採用回溯法解決問題時,可以使用約束條件對左子樹進行剪枝,使用限界條件對右子樹進行剪枝。在本題中,約束條件為tw w i c,限界條件...

回溯法解決0 1揹包問題

1.回溯法可以看作是窮舉法的一種實現方式 2.基本過程 每一步只生成解的一部分 部分解 並立即對該部分解進行評估,若有可能擴充套件成為 所求解 則繼續擴充套件,得到新的部分解,泛指嘗試其他部分解,知道窮盡所有可能.3.解空間 所有的可能的解的集合 解空間樹 將解空間組織成樹形成的樹形結構 常見的解空...

回溯法解決01揹包問題

一 問題描述 有n 個物品,它們有各自的重量和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?二 總體思路 因為回溯求解的規則是 後進先出 所以要用棧來存放符合條件的解,在儲存過程中用陣列來存放各個物品的體積和價值,然後用深度優先搜尋的方式求解,最後得到符合條件的最優解並輸出。三...