Java實現N皇后問題的雙路徑探索:遞歸回溯與迭代回溯算法詳解

N皇后問題要求在N×N的棋盤上放置N個皇后,使得她們無法互相攻擊。本文提供遞歸和循環迭代兩種解法,并通過圖示解釋核心邏輯。


一、算法核心思想

使用回溯法逐行放置皇后,通過沖突檢測保證每行、每列、對角線上只有一個皇后。發現無效路徑時回退到上一狀態。

沖突檢測條件(關鍵):
  1. 同列沖突:col[i] == col[j]
  2. 對角線沖突:abs(col[i] - col[j]) == abs(i - j)

二、遞歸版本實現

  1. 流程圖

  1. 時序圖

  1. 代碼解釋

  1. 程序目的
    該代碼用于解決N皇后問題,即在N×N棋盤上放置N個皇后,使其互不攻擊(即任意兩個皇后不在同一行、列或對角線上),返回所有可能的解。
  2. solveNQueens方法
    • 初始化結果列表result,用于存儲所有解。
    • 調用backtrack方法啟動遞歸回溯過程。
    • 參數n表示棋盤大小,cols數組記錄每行皇后所在的列位置(索引為行,值為列)。
  3. backtrack遞歸核心
    • 終止條件:當row == n時,表示所有皇后已正確放置,將當前cols數組的拷貝加入結果(避免后續修改影響結果)。
    • 遞歸邏輯:遍歷當前行的每一列col,若位置有效則放置皇后(cols[row] = col),并遞歸處理下一行(row + 1)。
  4. isValid沖突檢查
    • 檢查當前列col與之前所有行(0row-1)的皇后是否沖突:
      • 列沖突cols[i] == col,即同一列已有皇后。
      • 對角線沖突Math.abs(col - cols[i]) == row - i,即行差等于列差絕對值。
    • 若任一條件滿足,返回false,否則位置有效。
  5. 主函數測試與輸出
    • 測試n=4的皇后問題,調用solveNQueens獲取所有解。
    • 使用Lambda表達式遍歷打印每個解(如[1, 3, 0, 2]表示第0行皇后在1列,第1行在3列等)。
  6. 關鍵實現細節
    • 回溯剪枝:僅嘗試有效位置,減少遞歸次數。
    • 結果存儲:每次成功時創建新的ArrayList保存當前解,避免引用問題。
    • 遞歸層次:每層遞歸處理一行皇后,確保每行只有一個皇后。

示例輸出:
對于n=4,輸出兩個解:[1, 3, 0, 2][2, 0, 3, 1],對應兩種不同的棋盤布局方式。

  1. 代碼實現
    1. 注意:下標從0開始
import java.util.ArrayList;
import java.util.List;public class NQueensRecursive {public static List<List<Integer>> solveNQueens(int n) {List<List<Integer>> result = new ArrayList<>();backtrack(n, 0, new Integer[n], result);return result;}private static void backtrack(int n, int row, Integer[] cols, List<List<Integer>> result) {if (row == n) {result.add(new ArrayList<>(List.of(cols)));return;}for (int col = 0; col < n; col++) {if (isValid(cols, row, col)) {cols[row] = col;backtrack(n, row + 1, cols, result);}}}private static boolean isValid(Integer[] cols, int row, int col) {for (int i = 0; i < row; i++) {if (cols[i] == col || Math.abs(col - cols[i]) == row - i) {return false;}}return true;}public static void main(String[] args) {List<List<Integer>> solutions = solveNQueens(4);solutions.forEach(System.out::println);}
}


三、循環迭代版本實現

  1. 時序圖

  1. 流程說明
  1. 初始化階段
    • 清空皇后位置數組
    • 從第一個皇后開始放置(j=1)
  2. 主循環邏輯
    • 每次循環嘗試將當前皇后的位置右移一格
    • 通過check()驗證當前位置是否:
      • 與已有皇后同列
      • 處于同一斜線
    • 合法時繼續處理下一個皇后,非法時繼續右移
    • 當完成最后一列放置時輸出有效方案
  3. 回溯機制
    • 當某列所有位置嘗試失敗后
    • 重置當前列位置為0
    • 回溯到前一列繼續嘗試新位置
  4. 終止條件
    • 當回溯到j=0時說明所有可能性已窮盡
    • 程序正常結束

該實現通過非遞歸方式實現了經典的回溯算法,使用while循環和位置重置機制替代了遞歸調用棧,具有較好的空間效率。

  1. 代碼實現
    1. 注意:下標從1開始
public class Test {// 定義4個皇后static final  Integer N = 4;// 存儲皇后的列號static int[] q =  new int[N+1];// 方案數static int answer =0;public static void main(String[] args) {queen();}public static boolean check(int j){for(int i=1;i<j;i++){if(q[i]==q[j] || Math.abs(i-j)==Math.abs(q[i]-q[j])){ // 判斷是否同列或同一斜線return false;}}return true;}public static void queen(){queenInit();int j = 1; // 表示正在擺放第j個皇后while(j>=1){q[j] ++;// 讓第j個皇后的位置加1while(!check(j) && q[j]<=N){ // 不滿足條件的話,就一直向后移動,為了防止越界,還需要判斷q[j]的長度q[j]++;}// 判斷if(q[j]<=N){// 表示第j個位置,合法if(j==N){// 最后一個皇后已經擺放完畢了answer++;System.out.print("方案"+answer);System.out.print("結果為:");for (int i = 1; i <=N ; i++) {System.out.print(q[i]+",");}System.out.println();}else{// 繼續找下一個皇后的擺放位置j++;}}else{// 沒有位置擺放了,需要回溯到上一次。q[j]=0; // 重置位置j--;}}}// 皇后初始化public static void queenInit(){for(int i=1;i<=N;i++){q[i]=0;}}
}


四、算法流程圖示(以4皇后為例)

步驟分解:
1. 放置行0的皇后在列0Q . . .. . . .. . . .. . . .2. 行1嘗試列0(沖突)→ 嘗試列1(沖突)→ 列2有效Q . . .. . Q .. . . .. . . .3. 行2嘗試所有列均沖突,回溯到行1Q . . .. . . . ← 行1無法繼續. . . .. . . .4. 行1移動到列3Q . . .. . . Q. . . .. . . .5. 行2嘗試列1有效Q . . .. . . Q. Q . .. . . .6. 行3無有效列,回溯→最終找到解:[1, 3, 0, 2] 對應棋盤:. Q . .. . . QQ . . .. . Q .

五、算法對比

特性遞歸版本循環迭代版本
代碼復雜度簡潔,易理解需手動管理狀態棧
內存消耗有棧深度限制顯式棧結構,可控性強
適用場景小規模數據,代碼可讀性優先避免棧溢出,大數據量更穩定

兩種方法時間復雜度均為O(N!),實際效率相近,選擇依據具體場景需求。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/75665.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/75665.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/75665.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端判斷值相等的方法和區別

1. (寬松相等) 在比較之前會進行類型轉換 可能導致一些意外的結果 0 // true 0 0 // true false 0 // true null undefined // true [1,2,3]1,2,3 // true2. (嚴格相等) 不進行類型轉換 類型和值都必須相同 0 // false 0 0 // false false 0 /…

Socket編程UDP

Socket編程UDP 1、V1版本——EchoServer2、網絡命令2.1、ping2.2、netstat2.3、pidof 3、驗證UDP——Windows作為client訪問Linux4、V2版本——DictServer5、V3版本——簡單聊天室 1、V1版本——EchoServer 首先給出EchoServer目錄結構&#xff1a;服務器的類我們實現在UdpServ…

輔助查詢是根據查詢到的文檔片段再去生成新的查詢問題

&#x1f4a1; 輔助查詢是怎么來的&#xff1f; 它是基于你當前查詢&#xff08;query&#xff09;檢索到的某個文檔片段&#xff08;chunk_result&#xff09;&#xff0c;再去“反推”出新的相關問題&#xff08;utility queries&#xff09;&#xff0c;這些問題的作用是&a…

2025 年 4 月補丁星期二預測:微軟將推出更多 AI 安全功能

微軟正在繼續構建其 AI 網絡安全戰略&#xff0c;并于本月宣布在 Microsoft Security Copilot 中引入新代理。 他們引入了用于網絡釣魚分類的代理、用于數據丟失預防和內部風險管理的警報分類、條件訪問優化、漏洞修復和威脅情報簡報。 這些代理的目標是不斷從這些不同學科中…

【LLM系列】1.大模型簡介

1. 基礎 1.1 如何權衡模型的復雜度和性能&#xff1f; ├── a. 模型架構選擇 │ ├── 簡化架構 │ │ └── 選擇較小的網絡層數和寬度&#xff0c;降低復雜度&#xff1b; │ │ 可使用高性能基礎模型如 Transformers 作為起點&#xff0c;根據需求縮放模型。 │ └──…

【leetcode】記錄與查找:哈希表的題型分析

前言 &#x1f31f;&#x1f31f;本期講解關于力扣的幾篇題解的詳細介紹~~~ &#x1f308;感興趣的小伙伴看一看小編主頁&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的點贊就是小編不斷更新的最大動力 &#x1f386;那么廢話不…

優選算法的妙思之流:分治——快排專題

專欄&#xff1a;算法的魔法世界 個人主頁&#xff1a;手握風云 目錄 一、快速排序 二、例題講解 2.1. 顏色分類 2.2. 排序數組 2.3. 數組中的第K個最大元素 2.4. 庫存管理 III 一、快速排序 分治&#xff0c;簡單理解為“分而治之”&#xff0c;將一個大問題劃分為若干個…

二叉樹的ACM板子(自用)

package 二叉樹的中序遍歷;import java.util.*;// 定義二叉樹節點 class TreeNode {int val; // 節點值TreeNode left; // 左子節點TreeNode right; // 右子節點// 構造函數TreeNode(int x) {val x;} }public class DMain {// 構建二叉樹&#xff08;層序遍歷方式&…

Linux常用命令詳解:從基礎到進階

目錄 一、引言 二、文件處理相關命令 &#xff08;一&#xff09;grep指令 &#xff08;二&#xff09;zip/unzip指令 ?編輯 &#xff08;三&#xff09;tar指令 &#xff08;四&#xff09;find指令 三、系統管理相關命令 &#xff08;一&#xff09;shutdown指…

Qt多線程從基礎到性能優化

一、為什么需要多線程開發 現代應用程序的性能需求 CPU多核架構的有效利用 復雜任務的解耦與響應式界面保持 二、Qt線程創建四大方式 1. 繼承QThread重寫run() class WorkerThread : public QThread {void run() override {// 耗時操作qDebug() << "Thread ID…

【java】在 Java 中,獲取一個類的`Class`對象有多種方式

在 Java 中&#xff0c;獲取一個類的Class對象有多種方式。Class對象代表了 Java 中的一個類或接口的運行時類信息&#xff0c;可以用于反射操作。以下是獲取Class對象的幾種常見方法&#xff1a; 1.使用.class屬性 每個類都有一個.class屬性&#xff0c;可以直接獲取該類的Cl…

什么是RPC通信

RPC&#xff08;Remote Procedure Call&#xff0c;遠程過程調用&#xff09;通信是一種允許程序像調用本地函數一樣調用遠程服務器上函數的通信技術。它簡化了分布式系統中的網絡交互&#xff0c;隱藏了底層網絡通信的復雜性&#xff0c;使開發者能夠專注于業務邏輯。 一、RPC…

還是主題混合程序設計

以下是針對您現有代碼的完整主題化改造方案&#xff0c;實現跨QML/Qt Widgets的陰影主題系統&#xff1a; 一、主題管理系統核心 // thememanager.h #pragma once #include <QObject> #include <QColor> #include <QMap> #include <QQmlEngine>class…

BT-Basic函數之首字母T

BT-Basic函數之首字母T 文章目錄 BT-Basic函數之首字母Ttabtesttest conttest monitortest on boardstest scanworkstest shortstesthead cleanuptesthead configurationtesthead istesthead power on/offtesthead statustestjet print level istestordertestplan generationth…

7-9 趣味游戲

題目解析 在某個學校的趣味游戲活動中&#xff0c;N 名同學站成一排&#xff0c;他們的年齡恰好是 1 到 N &#xff0c;需要注意的是他們并不是按照年齡的大小排列的&#xff0c;而是隨機排列的。 游戲的規則是請同學們快速計算出&#xff0c;如果在這 N 名同學的小組中&…

Hugging Face模型微調訓練(基于BERT的中文評價情感分析)

文章目錄 學習視頻地址項目地址數據集的下載模型微調的基本概念與流程加載數據集數據集格式數據集信息 制作Dataset數據集字段數據集信息 vocab字典操作詞匯表文本轉換 下游任務模型設計模型訓練與保存數據加載優化器訓練循環 最終效果評估與測試模型加載和測試 學習視頻地址 …

【藍橋杯】十五屆省賽B組c++

目錄 前言 握手問題 分析 排列組合寫法 枚舉 小球反彈 分析 代碼 好數 分析 代碼 R 格式 分析 代碼 寶石組合 分析 代碼 數字接龍 分析 代碼 拔河 分析 代碼 總結 前言 主播這兩天做了一套藍橋杯的省賽題目&#xff08;切實感受到了自己有多菜&#x…

必刷算法100題之計算右側小于當前元素的個數

題目鏈接 315. 計算右側小于當前元素的 個數 - 力扣&#xff08;LeetCode&#xff09; 題目解析 計算數組里面所有元素右側比它小的數的個數, 并且組成一個數組,進行返回 算法原理 歸并解法(分治) 當前元素的后面, 有多少個比我小(降序) 我們要找到第一比左邊小的元素, 這…

Hyperlane框架:下一代高性能Rust Web框架 [特殊字符]

Hyperlane框架&#xff1a;下一代高性能Rust Web框架 &#x1f680; 引言 &#x1f44b; 在當今快速發展的Web開發領域&#xff0c;性能和開發效率的平衡變得越來越重要。Hyperlane作為一個新興的Rust Web框架&#xff0c;完美地解決了這個問題。本文將帶您深入了解Hyperlane…

圖像處理:使用Numpy和OpenCV實現傅里葉和逆傅里葉變換

文章目錄 1、什么是傅里葉變換及其基礎理論 1.1 傅里葉變換 1.2 基礎理論 2. Numpy 實現傅里葉和逆傅里葉變換 2.1 Numpy 實現傅里葉變換 2.2 實現逆傅里葉變換 2.3 高通濾波示例 3. OpenCV 實現傅里葉變換和逆傅里葉變換及低通濾波示例 3.1 OpenCV 實現傅里葉變換 3.2 實現逆傅…