回溯是一種系統地搜尋問題解答的方法。為了實現回溯,首先需要為問題定義乙個解的空間。而問題的解集合一般被組織成樹的形式(一般解所構成樹為邏輯樹不用去用**構建乙個解集合構成的樹)。然後以深度搜尋的方式去遍歷解集合,從而得到問題的解。可以使用限界函式來避免 對不可能求出解子集合的遍歷來優化回溯方法。
回溯方法求解的步驟:
1:定義乙個解的空間,它包含問題的解。
2:以適於搜尋的方式組織該空間,一般以一維陣列的形式組織成邏輯上的解空間樹(主要是滿二叉樹和排列數的形式)。
3:用深度優先法搜尋該空間,利用限界函式避免移動到不可能產生解的子空間。
回溯演算法可應用在貨箱裝船、揹包、最大完備子圖、旅行商、電路排列問題等,一般用來解決從解集合中對最優問題的求解。
在應用中由於候選解的數量都很大(指數級甚至大數的階乘級),而回溯法,在求解時間上大大減少。但其時間和空間複雜對還是相當奢侈的,在求解大規模問題中不是擁有「高富帥」配置的計算機玩的起的。對這些np問題的求解想得到多項式時間內「秒殺」,現在還是一種奢望。大都在指數級時間複雜度內。但在小規模問題中不失為一種好方法。回溯法的空間複雜度o(從開始節點起最長路徑長度)。
舉兩個例子觀摩一下,回溯法是怎麼把答案搜出來的。
乙個例子是貨箱裝船問題,它的解空間是以乙個一維陣列來構建乙個邏輯上的滿二叉樹。
問題場景:n 個貨箱,乙個貨船的載重量為c,wi是貨箱i的重量,且所有貨物之和大於c,求貨船最多裝多種的貨物。
假設n=4;w=[8,6,2,3],c=12;
按回溯法來分析問題,
1:構建解空間,有n個貨箱每個貨箱都有裝上船和不裝船兩種可能,所以n個貨箱就有2的n次方個解。這些解可組織成滿二叉樹的形式。如圖
邊權值為1表示貨物被裝上船,0便是貨物沒有裝上船。上面的二叉樹可以表示所有的解也就是解空間。
第i層的邊和第i個貨物對應,如果經過第i層,選擇的邊權值為1則第i個貨物被裝上船。從跟節點深度遍歷,每獲得乙個可行解,就與上一次獲得的解比較比上次的大則更新最優解。遍歷結束時就獲得了最後的解。
**如下:
templatevoid maxloading(t w,t c,int n);
templateclass loading
private:
void maxloading(int i);
void maxloading1(int i);
int n;//貨物數量
t* w;//貨物重量的陣列
t r;//剩餘貨物重量
int* x;//記錄當前搜尋路徑下的裝載情況
int* bestx;//記錄最優裝載的貨物編號
t c;//貨箱的容量
t cw;//當前重量
t bestw;//最優重量
};templatevoid loading::maxloading(int i)
if(cw+w[i]void loading::maxloading1(int i)
r-=w[i];
if(cw+w[i]<=c)
if(cw+r>bestw)
r+=w[i];
}templatevoid maxloading(t w,t c,int n)
maxloading和maxloading1的區別加了限制條件,並可以獲得裝載貨物的編號。
(有錯誤還望指正)
回溯法 演算法框架及應用
在包含問題的所有解的空間樹中,按照深度優先搜尋策略,從根節點出發搜尋解空間樹。活結點 自身已生成但其孩子結點沒有全部生成的結點 擴充套件結點 指正在產生孩子結點的結點,e結點 死結點 指其所有結點均已產生的節點 首先根節點成為活結點,同時也成為當前的擴充套件結點 在當前的擴充套件結點處,搜尋向縱深方...
回溯 leetcode回溯演算法
回溯演算法實際上乙個類似列舉的搜尋嘗試過程,主要是在搜尋嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就 回溯 返回,嘗試別的路徑。回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,...
深度優先遍歷回溯演算法的應用
void search int cur 這個模板就是目前我遇見的最簡潔的模板,用乙個二維陣列vis 3 其中vis 0 i 表示列,vis 1 i 和vis 2 i 表示對角線。因為 x,y 的y x值標識了主對角線,x y值標識了副對角線。由於y x可能為負,所以訪問時要加上n。下面主要介紹一下主...