1.概念
回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。
回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。
許多複雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。
2.基本思想
在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。(其實回溯法就是對隱式圖的深度優先搜索算法)。
若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。
而若使用回溯法求任一個解時,只要搜索到問題的一個解就可以結束。
白話:回溯法可以理解爲通過選擇不同的岔路口尋找目的地,一個岔路口一個岔路口的去嘗試找到目的地。如果走錯了路,繼續返回來找到岔路口的另一條路,直到找到目的地。
3.用回溯法解題的一般步驟:
1)針對所給問題,確定問題的解空間:首先應明確定義問題的解空間,問題的解空間應至少包含問題的一個(最優)解。
2)確定結點的擴展搜索規則
3)以深度優先方式搜索解空間,並在搜索過程中用剪枝函數避免無效搜索。
4. 實例:解決N皇后問題
-
問題: 在n*n格的棋盤撒上放置彼此不受攻擊的n個皇后。按照國際象棋的規矩,皇后可以攻擊與之處在同一行或者同一列或者同一斜線上的棋子。N皇后問題等價於在n * n格的棋盤上放置n個皇后,任何2個皇后不放在同一行同一列同一斜線上。
-
分析: 可以將nn的棋盤看成一個nn的表格,放置皇后Q,且需要滿足兩個條件
- 條件1:同行同列不能放置兩個或大於兩個皇后
- 條件2:皇后的斜線上不能存在皇后
-
解題思路及步驟:
逆推導:行值是列表的第幾個元素,列值是列表元素的值
那麼,可以知道,當列表中出現兩個或者兩個以上的相同元素時,即不滿足條件1
爲了提高算法效率,我們可以將不考慮限制條件和考慮條件1相結合,那麼就是全排列算法
1 2 3 4
1♛ ☐ ☐ ☐
2☐ ♛ ☐ ☐
3☐ ☐ ♛ ☐
4☐ ☐ ☐ ♛
從以上模型可得,
i,j表示行值,a[i],a[j]表示列值
|a[i]-a[j]| = |i-j|,即不滿足條件2
|a[i]-a[j]| != |i-j|,即滿足條件2
滿足條件2,可以將滿足條件1問題的所有解空間,進行條件限制,可以通過函數實現,這個函數即是剪枝函數
編程步驟:
首先定義一個列表,爲素材列表[1,2,3,…,n]
定義一個列表,存儲全排列的結果;對素材列表進行全排列,並存入該列表中,爲全排列列表
定義一個列表,用於存儲滿足條件2的列表,爲結果列表
根據結果列表,進行格式打印
代碼實現
#全排列函數
per_result = []
def per(lst,s,e):
if s == e:
per_result.append(list(lst))
else:
for i in range(s,e):
lst[i],lst[s] = lst[s],lst[i]#試探
per(lst,s+1,e)#遞歸
lst[i],lst[s] = lst[s],lst[i]#回溯
#剪枝函數
def shear(lst):
result = 0
for i in range(len(lst)):
for j in range(i+1,len(lst)):
if(abs(lst[j] - lst[i]) == abs(j-i)):
result += 1
if(result > 0):
return True
else:
return False
#格式打印函數
def stamp(st):
for i in st:
for j in range(len(i)):
a = ("☐"*(i[j]-1)+"♛"+"☐"*(len(i)-i[j]))
print(a,"\t","第{}個皇后放在棋盤的第{}列".format(j+1,i[j]))
print(" ")#負責空行
def main():
num = eval(input("請輸入皇后的個數:"))
lst = [i+1 for i in range(num)]
per(lst,0,num)
queen_lst = []
for i in per_result:
if(shear(i) == False):
queen_lst.append(i)
stamp(queen_lst)
print("共{:d}種可能".format(len(queen_lst)))
if __name__=='__main__':
main()
輸出樣例:
4皇后:
8皇后:
參考文章:
https://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html
https://blog.csdn.net/zhj_1121/article/details/103059144