1. 程式人生 > >Leetcode演算法——51~52、n皇后問題

Leetcode演算法——51~52、n皇后問題

n皇后問題需要將n個皇后放置在n*n的棋盤上,保證任意兩個皇后都不能處於同一行、同一列或同一斜線上。

51、給定一個整數n,返回n皇后問題的所有不重複的解。
51、給定一個整數n,返回n皇后問題的所有不重複的解的個數。

每個解都是一種n個皇后的佈局,其中 ‘Q’ 和 ‘.’ 分別代表皇后和空白。

示例:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

思路

n皇后問題是典型的回溯法教材。

所謂回溯法,是在遞迴的基礎上,增加了回溯(即反悔的操作),先假設我採用方法A解決當前問題,然後繼續遞迴剩下的任務,最後回過頭來進行反悔,不這樣做了,而改用方法B來解決這個問題,然後繼續遞迴。

使用回溯法,能夠實現對所有滿足要求情況的列舉,同時最大程度減少不滿足要求的列舉(因為一旦中間某個過程不滿足要求,則剩下的過程不再繼續遞迴)

以n皇后為例,可以這樣做:

  • 初始化一個n*n的空棋盤
  • 嘗試在第1行第1列中安放一個皇后,判斷放在這裡之後整個棋盤是否尚且滿足要求,如果滿足,則繼續遞迴第2行;如果不滿足,則回溯:將皇后從第1行第1列刪掉,改為放在第1行第2列。
  • 繼續判斷放在第1行第2列之後整個棋盤是否滿足要求,以此類推。
  • 遞迴結束:一旦最後一行中某一列安放一個皇后,可以使得整個棋盤滿足要求,那麼便求出了一個解。
  • 我們要求尋找到所有不重複的解,因此這時演算法還不能結束,繼續回溯:倒數第2行的皇后向右移動一格,繼續遞迴。
  • 直至所有迴圈都退出。

python實現

def solveNQueens(n):
    """
    :type n: int
    :rtype: List[List[str]]
    回溯法。
    """
    
    def place_queen(result_list, place_list,
cur_row): ''' 在第 cur_row 行上放置一個皇后。 result_list:存放所有的解 place_list:長度為n,每一個元素代表這一行上的皇后的位置 ''' # 遞迴結束條件 if cur_row == len(place_list): # 將答案轉為二維棋盤,放入到result_list中 # 如果是返回解的個數,則不需要轉為二維棋盤,直接統計result的個數即可 result_list.append(['.'*i + 'Q' + '.'*(n-i-1) for i in place_list]) return # 在cur_row這一行上對所有位置依次嘗試放置皇后 for cur_col in range(n): place_list[cur_row] = cur_col # 判斷是否有同行同列同斜邊的皇后 for row in range(cur_row): col = place_list[row] if col == cur_col or abs(cur_col - col) == cur_row - row: break else: # 沒有break,說明有效,繼續放置下一行 place_queen(result_list, place_list, cur_row + 1) result_list = [] place_queen(result_list, [0] * n, 0) return result_list def output_board(board_list): ''' 輸出棋盤 ''' print(f'共{len(board_list)}種解法') for board in board_list: print(' ') for row in board: print(row) if '__main__' == __name__: n = 4 output_board(solveNQueens(n))