演算法 回溯法 0 1揹包問題

2021-08-20 03:29:19 字數 2127 閱讀 2105

fishing-pan:

回溯法是一種非常有效的方法,有「通用的解題法」之稱。它有點像窮舉法,但是更帶有跳躍性和系統性,他可以系統性的搜尋乙個問題的所有的解和任一解。回溯法採用的是深度優先策略。

回溯法解決問題一般分為三個步驟;

(1)針對所給問題,定義問題的解空間;

(2)確定易於搜尋的解空間結構;

(3)以深度優先的方式搜尋解空間。

為了方便理解回溯法運算的流程,以0-1揹包問題為例進行分析;

問題:給定乙個載重量為w,n個物品,物品的重量為wi,價值為vi,1<=i<=n,要求:把物品裝入揹包,並使包內物品價值最大。

int bound(int *values, int *weights,int n,int maxweight,int num,int current_weight,int current_profit)

//--------------num為已選中的最後乙個物品的編號,current_weight為現在的重量,current_profit為現有價值

else

}return current_profit;

}

下面的**實現在解空間進行搜尋的過程;

int *knapsack(int *values,int *weights,int n,int maxweight)

} //否則就是由於第i個物品在當前情況下無法放入揹包

else

while (bound(values, weights, n, maxweight, i, current_weight, current_profit) <= profit)//如果不可能獲得更大的價值,那麼這個點就不需要進行擴充套件了;

if (i == 0) //當回溯到i=0時候,所有情況都遍歷了

x[i] = unselect;

current_profit -= values[i];

current_weight -= weights[i];

} i++; }

}

假設n=8,w=110;物品的價值和重量如下表(已按照單位價值排序);

物品 i12

3456

78vi11

2131

3343

5355

65wi111

2123

3343

4555

那麼問題的解空間就很明顯了就是2的8次方個種問題的解的組合。

使用二叉樹構建解空間,這裡解空間的乙個結點共有兩個候選值0、1 。 0代表不放進揹包中(右子樹), 1代表放進揹包中(左子樹),如下圖所示;

採用深度優先策略進行搜尋,搜尋的過程如下所示;

搜尋得到的最終的結果就是159;

從第乙個點開始向下擴充套件,擴充套件到將第四個點放入放入後,此時揹包已經放入重量為56,價值為96。然後繼續擴充套件,將第五個物品放入重量為89,價值為139。此時第六個物品無法繼續放入,但是i=5的,也就是沒有到達最後乙個點,此時呼叫bound()函式算出可能獲得的最大的價值為164.66,那麼繼續向下擴充套件,但是無法放入物品了,繼續呼叫bound()判斷是否向下擴充套件,直到最後乙個物品也無法放入,確定此時搜尋得到的可以獲得的最大的價值為139,儲存物品放入的選擇。

然後開始回溯,回溯遇到第乙個放入揹包的物品對應的節點,將其取0(把物品拿出揹包,進入右子樹)。此時比較揹包剩餘重量,發現第六個物品可以放入揹包,放入後背包重量為99,價值為149。但是,第七個物品無法繼續放入,那麼呼叫bound(),發現可能獲得162的價值,大於139,繼續向下擴充套件,直到最後乙個物品也無法放入,確定此時搜尋得到的可以獲得的最大的價值為149>139,更新可獲得的價值,並且儲存物品放入的選擇。

繼續回溯,直到回溯到根結點。此時的最大價值所對應的物品放入選擇就是所求的解。

在最壞的情況下,所搜尋的結果是乙個滿二叉樹,此時相當於採用的就是窮舉法,時間複雜度為

已完。。。。

回溯法 0 1揹包問題

0 1揹包問題 給定n種物品和一揹包.物品i的重量是wi,其價值為ui,揹包的容量為c.問如何選擇裝入揹包的物品,使得裝入揹包中物品的總價值最大?分析 0 1揹包是子集合選取問題,一般情況下0 1揹包是個np問題.第一步 確定解空間 裝入哪幾種物品 第二步 確定易於搜尋的解空間結構 可以用陣列p,w...

0 1揹包問題 回溯法

0 1揹包問題 回溯法 一 專案描述 每種物品只有2 種選擇,分別為 裝入揹包或不裝入揹包,物品數和揹包容量已給定,計算裝入揹包物品的最大價值和最優裝入方案,用回溯法搜尋子集樹的演算法進行求解。二 演算法設計 a.物品有n種,揹包容量為c,分別用p i 和w i 儲存第i種物品的價值和重量,用x i...

回溯法 0 1揹包問題

include include using namespace std class knap void knap backtrack int i 對第i個物品進行操作 return 如果沒有到葉子節點,就要對這個節點進行操作,即搜尋它的子樹,進入做左子樹表示可以選第i個,進入右子樹表示不能選第i個 ...