N皇后之回溯算法小結

題目介紹:51. N皇后
先給出答案:

class Solution(object):
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        使用最基礎的回溯算法,決策樹遍歷
        """
        import copy
        
        if n == 0: return []
        res = []
        path = [['.' for _ in range(n)] for _ in range(n)]  # 申請列表類型變量,因爲python字符串不能直接修改某個字符
        direction = [[-1, -1, -1, 0, 0, 1, 1, 1],
                     [-1, 0 ,1, -1, 1, -1, 0, 1]]  # 分別表示上下左右 左上 左下 右上 右下

        # 判斷當前位置是否合法,此處可以優化,因爲當前元素上方、左下角和右上角的元素不需要判斷
        def can(i, j):
            for biger in range(1, n+1):  # 一層一層向8個方向擴展,像泛起的水花
                for k in range(8): 
                    nexti = i + direction[0][k]*biger
                    nextj = j + direction[1][k]*biger
                    if nexti >= 0 and nexti < n and nextj >= 0 and nextj < n:
                        if path[nexti][nextj] == 'Q':
                            return False
            return True

        # 判斷第i層可以放置的所有位置(當前行的所有位置),i從0開始
        def back_track(path, i):
            # 結束條件
            if i == n:
                res.append(copy.deepcopy(path))  # 注意使用深拷貝
                return

            for j in range(n):  # 遍歷當前層的所有選擇
                if can(i, j) == False:  # 判斷第i層的j位置是否合法,進行剪枝操作
                    continue
                path[i][j] = 'Q'  # 做選擇
                back_track(path, i+1)  # 回溯
                path[i][j] = '.'  # 撤銷選擇

        back_track(path, 0)
        str_res = [[''.join(line) for line in m] for m in res]  # 轉換格式
        return str_res

# s = Solution()
# print(s.solveNQueens(4))

# 小實驗用於測試
# path = [['.', '.' , '.'], ['.', '.' , '.']]
# a = path[:][:]
# path[1][0] = 'O'
# print(a)
# a = '....'
# a[1] = 'o'
# print(a)
  • 回溯實際上是遍歷決策樹,通過遍歷每一種情況,從而確定哪些路徑符合要求,其中時間複雜度爲O(n!),比如在不含重複元素的“全排列”中,共有n!種解。這也是回溯算法的⼀個特點,不像動態規劃存在重疊⼦問題可以優化,回溯算法就是純暴⼒窮舉,複雜度⼀般都很⾼。
  • 基本代碼流程
result = []
def backtrack(路徑, 選擇列表):
	if 滿⾜結束條件:
		result.add(路徑)
	return
	
for 選擇 in 選擇列表:
	做選擇  # 對應樹的前序遍歷
	backtrack(路徑, 選擇列表)
	撤銷選擇  # 對應樹的後續遍歷

ps:前序遍歷的代碼在進⼊某⼀個樹的節點之前的那個時間點執⾏,後序遍歷代碼在離開某個節點之後的那個時間點執⾏。我們要在遞歸之前做出選擇,在遞歸之後撤銷剛纔的選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章