首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

八皇後問題:遞歸回溯與迭代非遞歸兩種解法完整實現

     編輯:Java 綜合教學

問題描述

在 8×8 棋盤上放置 8 個皇後,使任意兩個皇後不同行、不同列、不同斜線。輸出所有合法擺放方案總數(經典結果為 92 種)。

核心數學判斷條件

設第 j 行皇後列位置為 x[j],第 k 行為 x[k]。衝突條件:

  • 同列:x[j] == x[k]
  • 同斜線:|j - k| == |x[j] - x[k]|(行差等於列差)

只要不滿足上述任一條件,即為合法位置。

解法一:遞歸深度優先搜索(DFS)

public class EightQueensRecursive {
    private int n = 8;        // 皇後數/棋盤大小
    private int sum = 0;      // 解計數
    private int[] x = new int[n + 1]; // 1-based 索引:x[i] 表示第 i 行皇后列號

    public void solve(int row) {
        if (row > n) {        // 所有行已放置完畢,找到一個解
            sum++;
            printSolution();
            return;
        }
        for (int col = 1; col <= n; col++) {
            x[row] = col;     // 嘗試在第 row 行第 col 列放置
            if (isValid(row)) // 剪枝:檢查與前 row-1 行是否衝突
                solve(row + 1);
        }
    }

    private boolean isValid(int k) {
        for (int j = 1; j < k; j++) {
            if (x[j] == x[k] || Math.abs(j - k) == Math.abs(x[j] - x[k]))
                return false;
        }
        return true;
    }

    private void printSolution() {
        System.out.print("解 " + sum + ": ");
        for (int i = 1; i <= n; i++) System.out.print(x[i] + " ");
        System.out.println();
    }

    public static void main(String[] args) {
        new EightQueensRecursive().solve(1);
        System.out.println("總解數: " + new EightQueensRecursive().sum); // 輸出 92
    }
}

解法二:非遞歸回溯(迭代 + 顯式棧模擬)

public class EightQueensIterative {
    private int n = 8;
    private int sum = 0;
    private int[] x = new int[n + 1]; // 1-based

    public void solve() {
        int row = 1; // 當前處理行
        while (row >= 1) {
            x[row]++; // 嘗試下一列
            // 在當前行尋找合法列
            while (x[row] <= n && !isValid(row)) {
                x[row]++;
            }
            if (x[row] <= n) { // 找到合法列
                if (row == n) { // 最後一行,得到一個解
                    sum++;
                    printSolution();
                } else {
                    row++; // 轉入下一行
                }
            } else { // 當前行無合法列,回溯
                x[row] = 0; // 重置當前行
                row--;      // 退回上一行
            }
        }
    }

    private boolean isValid(int k) {
        for (int j = 1; j < k; j++) {
            if (x[j] == x[k] || Math.abs(j - k) == Math.abs(x[j] - x[k]))
                return false;
        }
        return true;
    }
    // printSolution 同遞歸版
}

兩種解法對比

維度遞歸 DFS迭代回溯
代碼可讀性高,符合人類直覺中,需理解顯式狀態機
棧溢出風險深度受限於 JVM 棧(N>1000 可能溢出)無風險,堆上模擬棧
性能略高(方法調用開銷)略低(循環開銷),差異可忽略
調試便利性調用棧清晰需觀察變量狀態

擴展思考

  • N 皇後通用解:將 n=8 改為參數,支持任意 N。
  • 位運算優化:用整數位掩碼表示列、主對角線、副對角線佔用,極大提升速度(微秒級解 14 皇後)。
  • 對稱性剪枝:利用棋盤對稱性,只搜索一半首行位置,結果乘 2(處理中間列特例)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved