概念:
回溯法是一種非常有效的方法,有「通用的解題法」之稱。它有點像窮舉法,但是更帶有跳躍性和系統性,他可以系統性的搜尋乙個問題的所有的解和任一解。回溯法採用的是深度優先策略。
三個步驟:
針對所給問題,定義問題的解空間;
確定易於搜尋的解空間結構;
以深度優先的方式搜尋解空間。
優化方法:
搜尋過程使用剪枝函式來為了避免無效的搜尋。剪枝函式包括兩類:
使用約束函式,剪去不滿足約束條件的路徑;
使用限界函式,剪去不能得到最優解的路徑。
解空間樹分為兩種:子集樹和排列樹。兩種在演算法結構和思路上大體相同。
所給的問題是從n個元素的集合s中找出滿足某種性質的子集時,相應的解空間成為子集樹。
如0-1揹包問題,從所給重量、價值不同的物品中挑選幾個物品放入揹包,使得在滿足揹包不超重的情況下,揹包內物品價值最大。它的解空間就是乙個典型的子集樹。
回溯法搜尋子集樹的演算法正規化如下:
void backtrack (int t)
}
所給的問題是確定n個元素滿足某種性質的排列時,相應的解空間就是排列樹。
如旅行售貨員問題,乙個售貨員把幾個城市旅行一遍,要求走的路程最小。它的解就是幾個城市的排列,解空間就是排列樹。
回溯法搜尋排列樹的演算法正規化如下:
void backtrack (int t)
}
0-1揹包問題
問題:給定n種物品和一揹包。物品i的重量是wi,其價值為pi,揹包的容量為c。問應如何選擇裝入揹包的物品,使得裝入揹包中物品的總價值最大?
**如下:
#include using namespace std;
#define n 100 //預設有99個物品。第乙個不使用
int w[n]; //每個物品的重量
int v[n]; //每個物品的價值
int x[n]; //x[i]=1:物品i放入揹包,0代表不放入
int n,c; //n:一共有多少物品,c:揹包的最大容量
/**curweight 和 curvalue儲存當前放入揹包的資料,隨著對解空間的不斷深入而變化
*/int curweight = 0; //當前放入揹包的物品總重量
int curvalue = 0; //當前放入揹包的物品總價值
/**bestvalue 和 bestx在找到乙個葉子節點時進行 約束函式 判斷,滿足的話就連同修改儲存的最優解
*/int bestvalue = 0; //最優值;當前的最大價值,初始化為0
int bestx[n]; //最優解;bestx[i]=1代表物品i放入揹包,0代表不放入
void input()
cout
}void output()
}else
else //放入揹包}}
}}int main(int argc, char* ar**)
程式執行結果:
回溯法 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個 ...