回溯演算法 演算法總結(四)

2021-07-03 13:07:58 字數 1707 閱讀 9249

回溯算法也叫試探法,它是一種系統地搜尋問題的解的方法。回溯演算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。用回溯演算法解決問題的一般步驟為:

1、定義乙個解空間,它包含問題的解。 

2、利用適於搜尋的方法組織解空間。

3、利用深度優先法搜尋解空間。

4、利用限界函式避免移動到不可能產生解的子空間。 

問題的解空間通常是在搜尋問題的解的過程中動態產生的,這是回溯演算法的乙個重要特性。

經典例子(n後問題):

要求在乙個n*n格的棋盤上放置n個皇后,使得她們彼此不受攻擊,即使得任何兩個皇后不能被放在同一行或同一列或同一斜線上(西洋棋中乙個皇后可以攻擊與之處在同一行或同一列或同一斜線上的其他任何棋子)。注意通常會多種可行的放置方案。

n皇后問題是np完全的,用回溯法求解:

(1)定義問題的解空間:用n元組x[1:n]表示它的解,即乙個可行的放置方案。其中x[i]表示皇后i放在棋盤的第i行第x[i]列。由於不允許將任何兩個皇后放在同一列,所以解向量中諸x[i]互不相同。而任何兩個皇后不能放在同一斜線上是問題的隱約束。在搜尋時,可通過這個斜線約束來剪去無效的子樹。將棋盤看作是二維方陣,從左上角到右下角的主對角線及其平行線上(即斜率為-1的各斜線),

元素的兩個下標值的差值相等。同理,斜率為+1的每一條斜線上,元素的兩個下標值的和相等。因此,若兩個皇后放置位置為(i,j)和(k,l),且i-j=k-l或i+j=k+l,則這兩個皇后處於同一斜線上。這裡兩個等式可統一表示為|i-k|=|j-l|。

(2)確定解空間樹的結構:可以用一棵完全n叉樹來表示n皇后問題的解空間。樹枝上用放置的列號來標記,從樹根到任一葉子結點的路徑都是一種放置方案。這個完全n叉樹共有n**n(即n的n次方)個葉子結點,因此遍歷解空間樹的演算法需要o(n**n)的時間複雜度。

(3)以深度優先方式搜尋整個解空間,找出所要的解:約束函式為plack(k),它用來測試將皇后k放在x[k]列是否與前面已放置的k-1個皇后都不在同一列,且都不在同一斜線上。在回溯函式中,若搜尋到達葉子結點(i>n),則得到乙個新的n皇后互不攻擊的可行方案,可行方案數加1。若還未到達葉子結點(i<=n),由於是n叉樹,當前擴充套件結點有n個放置列號x[i]=1,2,...,n所表示的n個兒子結點,對皇后i的每一種列號放置情況,用結束函式place檢查其可行性,若可行則進入這個子樹進行遞迴搜尋,否則剪去這個子樹。演算法實現如下:

//問題及其解空間描述  

class queen;

//約束函式

bool queen::place(int k)

} //演算法實現函式:返回可行的放置方案個數,這裡陣列x的長度應該為n+1,

//x[1]~x[n]存放了其中的乙個可行放置方案

int nqueen(int* x,int n)

由於解空間樹有n**n(即n的n次方)個葉子結點,因此演算法的時間複雜度為o(n**n),非常耗時。回溯法有通用解題法之稱。因為它採用的是搜尋整個解空間的策略,對一些無從下手的、組合數較大的問題(特別是很多np完全問題),回溯法是乙個有力的工具。回溯法對解空間進行了有效的組織(組織成樹或圖的結構),還可以用剪枝函式來提高平均搜尋效率,因此它的效率大大高於純粹的窮舉法。

小結:

考試雖然已經過去,偶爾回首看看,還是有很多收穫的 。 回憶著寫這些部落格,可能有錯誤,也可能有一些理解不到的地方,如有問題,歡迎指正!

回溯演算法總結

回溯演算法這的題目很少,回溯法是一種組織搜尋的一般技術,有 通用的解題法 之稱,用它可以系統的搜尋乙個問題的所有解或任一解。有許多問題,當需要找出它的解集或者要求回答什麼解是滿足某些約束條件的最佳解時,往往要使用回溯法。可以系統地搜尋乙個問題的所有解或任意解,既有系統性又有跳躍性。回溯法的基本做法是...

LeetCode 回溯演算法總結

全排列 class solution void f vectorint res,vector int nums,vector int s,vector int visited for int i 0 isize i 子集 class solution void f vectorint result,...

演算法 回溯演算法

回溯演算法也叫試探法,它是一種系統地搜尋問題的解的方法。回溯演算法的基本思想是 從一條路往前走,能進則進,不能進則退回來,換一條路再試 1 有許多問題,當需要找出它的解集或者要求回答什麼解是滿足某些約束條件的最佳解時,往往要使用回溯法 2 回溯法的基本做法是搜尋,或是一種組織得井井有條的,能避免不必...