20190621-N皇後

来源:https://www.cnblogs.com/hyj691001/archive/2019/06/21/11062446.html
-Advertisement-
Play Games

N皇後 難度分類 困難 題目描述 n皇後問題研究的是如何將 n個皇後放置在 n×n 的棋盤上,並且使皇後彼此之間不能相互攻擊。 上圖為 8 皇後問題的一種解法。 給定一個整數 n,返回所有不同的 n 皇後問題的解決方案。 每一種解法包含一個明確的 n 皇後問題的棋子放置方案,該方案中 'Q' 和 ' ...


N皇後

難度分類

困難

題目描述

n皇後問題研究的是如何將 n個皇後放置在 n×n 的棋盤上,並且使皇後彼此之間不能相互攻擊。

 

 

上圖為 8 皇後問題的一種解法。

給定一個整數 n,返回所有不同的 n 皇後問題的解決方案。

每一種解法包含一個明確的 n 皇後問題的棋子放置方案,該方案中 'Q' 和 '.' 分別代表了皇後和空位。

示例:

輸入: 4

輸出: [

 [".Q..",  // 解法 1

  "...Q",

  "Q...",

  "..Q."],

 

 ["..Q.",  // 解法 2

  "Q...",

  "...Q",

  ".Q.."]

]

演算法圖示

Step1:遍歷第一行所有的列,先在第一行的第一個位置放置第一個皇後,第一個皇後放置後其對應的位置以及衝突位置如下:

Step2:遍歷第二行所有的列,發現第一第二列衝突,第三列個可以放第二個皇後,放置後如圖,放置後對應的位置以及衝突位置如下:

Step3: 遍歷第三行所有的列,發現沒有位置放置第三個皇後,所有列均衝突,所有此種情況下第三行無法放置第三個皇後(不可能得到最終解)。因此回到第二行,繼續遍歷第二行的第四列查看是否可以放置第二個皇後,放置後對應位置以及衝突位置如下:

Step4: 在調整了第二個皇後的位置後繼續遍歷第三行所有的列,發現第二列可以放置第三個皇後,放置後對應位置以及衝突位置如下:Step3: 遍歷第三行所有的列,發現沒有位置放置第三個皇後,所有列均衝突,所有此種情況下第三行無法放置第三個皇後(不可能得到最終解)。因此回到第二行,繼續遍歷第二行的第四列查看是否可以放置第二個皇後,放置後對應位置以及衝突位置如下:

Step5: 遍歷第四行所有的列,發現沒有位置放置第三個皇後,所有列均衝突,此時回到第三步,遍歷第三行的第三四列查看是否可以放置第三個皇後,發現均衝突的情況下回到第二行發現第二行的皇後也無法調整位置了回到第一行,將第一行的皇後放在第二列,繼續求解放置後對應位置以及衝突位置如下:

Step6: 在第一行第二列的基礎上查看第二行/第三行/第四行依次這樣每行的查找,當檢查完第一行所有的列後嘗試完所有的結果。

 

演算法

根據上面的圖示,這種搜索嘗試過程中尋找問題的解,但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇。這種解題方法我們可以很容易想到使用回溯演算法來解此題,將其轉換為演算法的步驟如下:

演算法第一步

找出約束函數用於去除不合法的解,如圖示中已經在第一行第一列的位置放置了皇後的情況下,如果查找放置第二個皇後的約束條件。這裡的約束條件如下:

01

02

03

04

11

12

13

14

21

22

23

24

31

32

33

34

 

  1. 判斷每次輸入的皇後是否在同一行同一列
  2. 判斷每次輸入的皇後與以前的皇後是否在同一 ‘/’ 斜線上的位置,此種情況下橫縱坐標之和相同
  3. 判斷每次輸入的皇後與以前的皇後是否在同一 ‘\’ 斜線上的位置,此種情況下橫縱坐標之差相同

轉換為偽代碼,假定設置2個變數,一個place_queens存放已放置皇後的位置的縱坐標,一個new_queen記錄新來的皇後的位置的縱坐標:

  1. place_queens裡面的格式為[x1,x2,x3…],每個x值本身表示其所在的列的索引,每個x本身在place_queens裡面的索引表示其所在的行。比如[1,3,0]表示第一行放在第二列,第二行放在第四列,第三行放在第1列,
  2. 根據a步驟得知len(place_queens)-1表示已放置皇後的最後一行的行號,因此len(place_queens)表示新來的皇後的行號,new_queen的值表示列號
  3. 如果new_queen與現有place_queens裡面的值相等,則證明新皇後與以前的某一個皇後被放到同一列了,因此返回衝突True
  4. 如果新皇後的行號-新皇後的列號 = 某一已放置皇後的行號-某一已放置皇後的列號即len(placed_queens)-new_queen == pos - placed_queens[pos]則證明新皇後與以前的某一個皇後在同一“\”,因此返回衝突True
  5. 如果新皇後的行號+新皇後的列號 = 某一已放置皇後的行號+某一已放置皇後的列號即len(placed_queens)+new_queen == pos + placed_queens[pos]則證明新皇後與以前的某一個皇後在同一“/”,因此返回衝突True
  6. 其他情況不衝突,返回False

演算法第二步

實現主函數,根據演算法圖示我們可以知道八皇後的主要實現就是遍歷每一行的每一列,如果能放置皇後,則查看接下來的一行,如果不能放置皇後遍歷下一列,這樣遍歷完所有行的所有列,則可得出N皇後的所有解。得出主體函數就做了2件事:

  1. 從第一行開始遍歷該行的每一列,如果能放置皇後(不衝突),處理下一行,如果不能放置皇後(衝突),繼續遍歷該行的下一列
  2. 當處理到最後一行的時候,仍然遍歷最後一行的所有列,如果能放置皇後,則找到了一個解,將此解放入結果列表中

演算法第三步

我們已經得到了八皇後的解,將其轉換為如下格式:

[

 [".Q..",  // 解法 1

  "...Q",

  "Q...",

  "..Q."],

 

 ["..Q.",  // 解法 2

  "Q...",

  "...Q",

  ".Q.."]

]

根據前面的演算法我們得出N皇後的解的格式如[[1, 3, 0, 2], [2, 0, 3, 1]],映射到題目需要的解,則將[[1, 3, 0, 2], [2, 0, 3, 1]]轉換為需要的格式即可具體轉換過程為:

  1. 遍歷前聲明一個解的列表ans=[]
  2. 遍歷解的每一行,聲明每一行的解格式each_row = ['.']*n,
  3. 然後修改對應位置為Q,修改方式為each_row[row] =’Q’
  4. 修改後將each_row轉換為字元串插入ans中
  5. 遍歷結束後將ans插入result中
  6. 回溯剪枝
  7. 列表和字元串轉換

考點

回溯

代碼

def conflict(placed_queens,new_queen):
    '''約束函數,用於檢查新來的皇後(new_queen)是否和已放置的皇後(placed_queens)是否會互相攻擊,如果會返回True,否則返回False'''
    if new_queen in placed_queens:#如果新的皇後和之前的皇後放置在同一列,縱坐標相等
        return True
    for pos in range(len(placed_queens)):#place_queens裡面存儲皇後的格式為place_queens[橫坐標]=縱坐標
        if len(placed_queens)-new_queen == pos - placed_queens[pos]:#在同一 ‘\’ 斜線上的位置,橫縱坐標之差相等
            return True
        if len(placed_queens)+new_queen == pos + placed_queens[pos]:#同一 ‘/’ 斜線上的位置,橫縱坐標之和相等
            return True
    return False
def dfs(n, place_queens=[],result=[]):
    if len(place_queens) == n - 1:#如果是放置最後一個皇後,即最後一行檢查
        for i in range(n):#遍歷所有的列
            if not conflict(place_queens, i):#如果不衝突,放置皇後
                place_queens+=[i]# place_queens+=[i]為一個解
                #將解轉換為目標格式
                ans = []
                for pos in place_queens:
                    each_row = ['.']*n
                    each_row[pos] ='Q'
                    ans.append(''.join(each_row))
                result.append(ans)
    for i in range(n):#遍歷每行所有的列
        if not conflict(place_queens, i):#如果不衝突,放置皇後
            dfs(n, place_queens + [i],result)#檢查下一行可放置皇後位置,place_queens + [i]表示記錄當前不衝突的皇後值,放入place_queens中
    return result
print(dfs(5)

附加代碼-N皇後執行步驟輔助理解代碼

def confict(place_queens, new_queen):
    '''place_queens:已放皇後的位置;new_queen:當前要放的皇後的位置'''
    nextY = len(place_queens)
    if new_queen in place_queens:#如果要放的位置已經放過了,則肯定衝突
        return True
    '''判斷斜線'''
    for i in range(nextY):
        #print(len(state), pos, i, state[i])
        if nextY-new_queen == i-place_queens[i]: return True#是否在同一 ‘\’ 斜線上,如果要放的位置與現有皇後的位置處於正斜線上則衝突
        if nextY+new_queen == i+place_queens[i]: return True#是否在同一 ‘/’ 斜線上,如果要放的位置與現有皇後的位置處於反斜線上則衝突
    return False
def queens(num, place_queens=(),steps = 1):
    '''num:皇後的個數,place_queens:已放皇後的位置'''
    #查看放置皇後位置,Q表示皇後,x表示非皇後
    print('當前檢查第%s行,已放置皇後的位置:%s'%(steps,place_queens))
    if len(place_queens)==num-1:#如果前面已經放了num-1個位置了,當前即為最後一步,此時找到不衝突的位置,返回這個位置
        for column in range(num):
            if not confict(place_queens, column):
                print('-'*100)
                print('通知:找到了最後一行的皇後放置位置啦,現告知第%s行!!!'%(steps -1))
                print((column,))
                yield (column,)
    else:#如果當前不是最後一步
        for column in range(num):#遍歷當前行所有的位置
            if not confict(place_queens, column):#如果在當前行當前位置上放置皇後不衝突
                for result in queens(num, place_queens+(column,),steps+1):#就在當前位置上放置皇後,記錄place_queens

                    if steps!=1:
                        print('通知:我們是第%s行,我們已收到通知第%s行的皇後找到了啦,現告知第%s行!!!' % (steps,steps+1,steps-1))
                        print((column,) + result)
                    else:
                        print('通知:我們已經收到下層反饋,找到了一個解!!!')
                        print((column,) + result)
                        print('-' * 100)
                    yield (column,) + result
result = []
num = 4
for each_ans in queens(num):
    result.append(each_ans)
print()
print('最終解:',result)
print('轉換為皇後位置排列如下:')
print('-'*100)
for each_ans in result:
    for column in each_ans:
        temp = ['.'] * num
        temp[column] = 'Q'
        print(temp)
    print('-'*100)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 父組件主動獲取子組件的數據和方法 1.調用子組件的時候 定義一個ref <headerchild ref="headerChild"></headerchild> 2.在父組件裡面通過 this.$refs.headerChild.屬性 t his.$refs.headerChild.方法 子組件主 ...
  • 1、安裝charles,點擊幫助——ssl代理——在移動設備或遠程瀏覽器上安裝charles root證書,看到如下界面: 2、在手機保證和電腦連接同一個wifi的前提下,開啟手機代理,輸入伺服器地址:192.168.5.252,埠號為:8888,有時候新手機連接代理,charles會提示是否允許 ...
  • 概述 最近在學習netty的相關知識,也在看netty的源碼,光看不練假把式,所以也正好利用自己學習的機會寫幾篇netty的分析文章,主要還是一些源碼解析的文章,一方面有輸出會促使自己在看源碼,學習原理的過程中更系統,更深入,同時也能加強記憶,鞏固對知識的理解。 關於netty的簡介和應用我就不做介 ...
  • 1.SOA SOA(Service-Oriented Architecture)面向服務架構,將應用程式不同功能單元(稱為服務)進行拆分,並通過這些服務之間定義良好的介面和契約聯繫起來。 SOA 不是特定的規範,是一種技術思想,一種理念,上圖為 SOA 架構的參考模型。 SOA 是一種粗粒度、松耦合 ...
  • 實驗三、數據挖掘之決策樹 一、實驗目的 1. 熟悉掌握決策樹的原理, 2. 熟練掌握決策樹的生成方法與過程 二、實驗工具 1. Anaconda 2. sklearn 3. pydotplus 三、實驗簡介 決策樹是一個非參數的監督式學習方法,主要用於分類和回歸。演算法的目標是通過推斷數據特征,學習決 ...
  • 實驗一、數據處理之Numpy 一、實驗目的 1. 瞭解numpy庫的基本功能 2. 掌握Numpy庫的對數組的操作與運算 二、實驗工具: 1. Anaconda 2. Numpy 三、Numpy簡介 Numpy 的英文全稱為 Numerical Python,指Python 面向數值計算的第三方庫。 ...
  • 前言 開心一刻 十年前,我:我交女票了,比我大兩歲。媽:不行!趕緊分! 八年前,我:我交女票了,個比我小兩歲,外地的。媽:你就不能讓我省點心? 五年前,我:我交女票了,市長的女兒。媽:別人還能看上你?分了吧! 今年,我挺著大肚子踏進家門。媽:閨女啊,你終於開竅了 ! 前情回顧 Spring拓展介面之 ...
  • 反向整數 給定一個 32 位有符號整數,將整數中的數字進行反轉,如果超出整數的最大或者最小範圍返回0 更多文章查看個人博客 "個人博客地址:反向整數" 方法一 利用StringBuilder的reverse方法,將數字轉換成字元反轉然後再轉換回整數 java public int reverseIn ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...