算法:用Java遞歸回溯求解八皇后問題的所有解(共92種解)

八皇后問題,就是國際象棋上面的皇后,可以橫豎斜地走,很威風。國際象棋棋盤是8*8的,上面需要放8個皇后,這8個皇后無論橫縱斜,都無法攻擊到其他的皇后,這樣就是一個八皇后問題的解。今天我們就用Java來實現八皇后問題的所有解:

import java.util.HashSet;
import java.util.Set;

/**
 * @author LiYang
 * @ClassName EightQueens
 * @Description 八皇后問題的解決實現類
 * @date 2019/12/26 10:11
 */
public class EightQueens {

    /**
     * 檢測縱向的皇后是否符合條件
     * @param queen 皇后排列的位置
     * @param level 當前遍歷到的行
     * @return 縱向是否滿足條件
     */
    private static boolean isVerticalCorrect(int[] queen, int level) {
        //皇后橫向位置的集合
        Set<Integer> position = new HashSet<>();

        //將已遍歷行的皇后位置放入集合
        for (int i = 0; i < level; i++) {
            position.add(queen[i]);
        }

        //如果位置各不相同,則集合有當前行的項數,返回true
        //如果集合沒有當前行的項數,則豎直方向有重複,返回false
        return position.size() == level;
    }

    /**
     * 檢測斜線的皇后是否符合條件
     * @param queen 皇后排列的位置
     * @param level 當前遍歷到的行
     * @return 斜線是否滿足條件
     */
    private static boolean isObliqueCorrect(int[] queen, int level) {
        //已有的每一行逐行驗證
        for (int i = 0; i < level; i++) {

            //得到當前行的皇后位置
            int position = queen[i];

            //左偏移值
            int leftOffset = 0;

            //從當前數組的位置開始往左遍歷
            for (int left = i; left > 0; left--) {

                //左偏移值自增
                leftOffset ++;

                //如果左偏移未越界,且左邊行的皇后位置與當前皇后位置斜線重合
                if (i - leftOffset >= 0
                        && (position - leftOffset == queen[i - leftOffset]
                        || position + leftOffset == queen[i - leftOffset])) {

                    //則不符合條件
                    return false;
                }
            }

            //右偏移值
            int rightOffset = 0;

            //從當前數組的位置開始往右遍歷
            for (int right = i; right < level; right++) {

                //右偏移值自增
                rightOffset ++;

                //如果右偏移未超過當前行,且右邊行的皇后位置與當前皇后位置斜線重合
                if (i + rightOffset < level
                        && (position - rightOffset == queen[i + rightOffset]
                        || position + rightOffset == queen[i + rightOffset])) {

                    //則不符合條件
                    return false;
                }
            }
        }

        //經過了檢測,斜線上符合條件
        return true;
    }

    /**
     * 檢測當前的皇后排列是否滿足條件
     * @param queen 皇后排列的位置
     * @param level 當前遍歷到的行
     * @return 斜線是否滿足條件
     */
    private static boolean isCorrect(int[] queen, int level) {
        //先檢驗縱向是否重複(橫向必然只有一個)
        boolean vertical = isVerticalCorrect(queen, level);

        //縱向不符合,直接返回不符合
        if (!vertical) {
            return false;
        }

        //再檢驗對角線是否重複
        boolean oblique = isObliqueCorrect(queen, level);

        //斜線不符合,直接返回不符合
        if (!oblique) {
            return false;
        }

        //通過檢驗後,返回正確
        return true;
    }

    /**
     * 深拷貝數組
     * @param arr 待拷貝的數組
     * @return 拷貝的數組副本
     */
    private static int[] copyArr(int[] arr) {
        //新建數組
        int[] newArr = new int[arr.length];

        //逐一拷貝
        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i];
        }

        //返回拷貝好的數組副本
        return newArr;
    }

    /**
     * 八皇后算法的方法
     * @param queen 當前的皇后排列
     * @param level 當前要遍歷的行
     */
    private static void eightQueens(int[] queen, int level) {
        //如果當前的皇后排列狀態不滿足條件
        if (!isCorrect(queen, level)) {
            
            //結束當前遞歸分支,遞歸回溯到上一步
            return;
        }
        
        //如果已經所有行都遍歷完了,且經過了上面的檢驗
        if (level == 8) {

            //打印求得的八皇后解
            printEightQueens(queen);

            //結束當前遞歸分支
            return;
        }

        //當前行的8個位置遍歷
        for (int i = 0; i < 8; i++) {

            //當前行8個位置都試一下
            queen[level] = i;

            //遞歸嘗試下一行的8個位置
            eightQueens(copyArr(queen), level + 1);
        }
    }

    /**
     * 根據最終得到的皇后排列,打印出答案
     * @param queen 滿足條件的皇后排列
     */
    private static void printEightQueens(int[] queen) {
        //打印每一行的皇后棋盤
        for (int i = 0; i < queen.length; i++) {

            //根據皇后位置來打印每一行棋盤
            switch (queen[i]) {
                case 0: System.out.println("皇十十十十十十十"); break;
                case 1: System.out.println("十皇十十十十十十"); break;
                case 2: System.out.println("十十皇十十十十十"); break;
                case 3: System.out.println("十十十皇十十十十"); break;
                case 4: System.out.println("十十十十皇十十十"); break;
                case 5: System.out.println("十十十十十皇十十"); break;
                case 6: System.out.println("十十十十十十皇十"); break;
                case 7: System.out.println("十十十十十十十皇"); break;
            }
        }

        //打印空行,隔開答案
        System.out.println();
    }

    /**
     * 八皇后算法的驅動方法
     */
    public static void eightQueens() {
        //皇后的初始排列數組,都在左邊第一位
        int[] queen = new int[8];

        //從第一行開始
        int level = 0;

        //調用八皇后算法的遞歸方法
        eightQueens(queen, level);
    }

    /**
     * 運行八皇后求解算法,共92個解
     * 注意:本算法運用的是遞歸回溯法,就是遞歸先往深處走,如果
     * 已經不符合規則了,就回退一步,然後上一步再繼續往右遍歷並
     * 遞歸,直到找到符合規定的答案。這種回溯法,比起窮舉法,可
     * 以減少大量的無效皇后排列,時間複雜度也會低於窮舉法
     * @param args
     */
    public static void main(String[] args) {
        //調用八皇后算法的方法,控制檯得出答案
        eightQueens();
    }

}

運行EightQueens類的main方法,控制檯輸出了八皇后問題的92個解,本算法測試通過:

皇十十十十十十十
十十十十皇十十十
十十十十十十十皇
十十十十十皇十十
十十皇十十十十十
十十十十十十皇十
十皇十十十十十十
十十十皇十十十十

皇十十十十十十十
十十十十十皇十十
十十十十十十十皇
十十皇十十十十十
十十十十十十皇十
十十十皇十十十十
十皇十十十十十十
十十十十皇十十十

皇十十十十十十十
十十十十十十皇十
十十十皇十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十十皇十十十
十十皇十十十十十

皇十十十十十十十
十十十十十十皇十
十十十十皇十十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十
十十十十十皇十十
十十皇十十十十十

十皇十十十十十十
十十十皇十十十十
十十十十十皇十十
十十十十十十十皇
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十

十皇十十十十十十
十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十十十十皇
十十十十十皇十十
十十十皇十十十十

十皇十十十十十十
十十十十皇十十十
十十十十十十皇十
十十十皇十十十十
皇十十十十十十十
十十十十十十十皇
十十十十十皇十十
十十皇十十十十十

十皇十十十十十十
十十十十十皇十十
皇十十十十十十十
十十十十十十皇十
十十十皇十十十十
十十十十十十十皇
十十皇十十十十十
十十十十皇十十十

十皇十十十十十十
十十十十十皇十十
十十十十十十十皇
十十皇十十十十十
皇十十十十十十十
十十十皇十十十十
十十十十十十皇十
十十十十皇十十十

十皇十十十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十皇十十
十十十十十十十皇
十十十十皇十十十
皇十十十十十十十
十十十皇十十十十

十皇十十十十十十
十十十十十十皇十
十十十十皇十十十
十十十十十十十皇
皇十十十十十十十
十十十皇十十十十
十十十十十皇十十
十十皇十十十十十

十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
皇十十十十十十十
十十皇十十十十十
十十十十皇十十十
十十十十十十皇十
十十十皇十十十十

十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十
十十十十十皇十十

十十皇十十十十十
十十十十皇十十十
十皇十十十十十十
十十十十十十十皇
皇十十十十十十十
十十十十十十皇十
十十十皇十十十十
十十十十十皇十十

十十皇十十十十十
十十十十皇十十十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
十十十皇十十十十
十十十十十十皇十
皇十十十十十十十

十十皇十十十十十
十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十

十十皇十十十十十
十十十十皇十十十
十十十十十十十皇
十十十皇十十十十
皇十十十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十皇十十

十十皇十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十皇十十十
十十十十十十十皇
皇十十十十十十十
十十十十十十皇十
十十十皇十十十十

十十皇十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十十十皇十
皇十十十十十十十
十十十皇十十十十
十十十十十十十皇
十十十十皇十十十

十十皇十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十十十皇十
十十十十皇十十十
皇十十十十十十十
十十十十十十十皇
十十十皇十十十十

十十皇十十十十十
十十十十十皇十十
十十十皇十十十十
皇十十十十十十十
十十十十十十十皇
十十十十皇十十十
十十十十十十皇十
十皇十十十十十十

十十皇十十十十十
十十十十十皇十十
十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十皇十十十
十十十十十十皇十
皇十十十十十十十

十十皇十十十十十
十十十十十皇十十
十十十十十十十皇
皇十十十十十十十
十十十皇十十十十
十十十十十十皇十
十十十十皇十十十
十皇十十十十十十

十十皇十十十十十
十十十十十皇十十
十十十十十十十皇
皇十十十十十十十
十十十十皇十十十
十十十十十十皇十
十皇十十十十十十
十十十皇十十十十

十十皇十十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十

十十皇十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十十十皇
十十十十皇十十十
皇十十十十十十十
十十十皇十十十十
十十十十十皇十十

十十皇十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
十十十皇十十十十
皇十十十十十十十
十十十十皇十十十

十十皇十十十十十
十十十十十十十皇
十十十皇十十十十
十十十十十十皇十
皇十十十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十皇十十十

十十十皇十十十十
皇十十十十十十十
十十十十皇十十十
十十十十十十十皇
十皇十十十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十皇十十

十十十皇十十十十
皇十十十十十十十
十十十十皇十十十
十十十十十十十皇
十十十十十皇十十
十十皇十十十十十
十十十十十十皇十
十皇十十十十十十

十十十皇十十十十
十皇十十十十十十
十十十十皇十十十
十十十十十十十皇
十十十十十皇十十
皇十十十十十十十
十十皇十十十十十
十十十十十十皇十

十十十皇十十十十
十皇十十十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十皇十十
十十十十十十十皇
皇十十十十十十十
十十十十皇十十十

十十十皇十十十十
十皇十十十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十皇十十
十十十十十十十皇
十十十十皇十十十
皇十十十十十十十

十十十皇十十十十
十皇十十十十十十
十十十十十十皇十
十十十十皇十十十
皇十十十十十十十
十十十十十十十皇
十十十十十皇十十
十十皇十十十十十

十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十十皇十十

十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
皇十十十十十十十
十十皇十十十十十
十十十十皇十十十
十十十十十十皇十

十十十皇十十十十
十十十十十皇十十
皇十十十十十十十
十十十十皇十十十
十皇十十十十十十
十十十十十十十皇
十十皇十十十十十
十十十十十十皇十

十十十皇十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十皇十十十

十十十皇十十十十
十十十十十皇十十
十十十十十十十皇
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十
十皇十十十十十十

十十十皇十十十十
十十十十十十皇十
皇十十十十十十十
十十十十十十十皇
十十十十皇十十十
十皇十十十十十十
十十十十十皇十十
十十皇十十十十十

十十十皇十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十十十皇
十皇十十十十十十
十十十十皇十十十
皇十十十十十十十
十十十十十皇十十

十十十皇十十十十
十十十十十十皇十
十十十十皇十十十
十皇十十十十十十
十十十十十皇十十
皇十十十十十十十
十十皇十十十十十
十十十十十十十皇

十十十皇十十十十
十十十十十十皇十
十十十十皇十十十
十十皇十十十十十
皇十十十十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十

十十十皇十十十十
十十十十十十十皇
皇十十十十十十十
十十皇十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十十十皇十
十十十十皇十十十

十十十皇十十十十
十十十十十十十皇
皇十十十十十十十
十十十十皇十十十
十十十十十十皇十
十皇十十十十十十
十十十十十皇十十
十十皇十十十十十

十十十皇十十十十
十十十十十十十皇
十十十十皇十十十
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十皇十十

十十十十皇十十十
皇十十十十十十十
十十十皇十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十十十十皇十
十十皇十十十十十

十十十十皇十十十
皇十十十十十十十
十十十十十十十皇
十十十皇十十十十
十皇十十十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十皇十十

十十十十皇十十十
皇十十十十十十十
十十十十十十十皇
十十十十十皇十十
十十皇十十十十十
十十十十十十皇十
十皇十十十十十十
十十十皇十十十十

十十十十皇十十十
十皇十十十十十十
十十十皇十十十十
十十十十十皇十十
十十十十十十十皇
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十

十十十十皇十十十
十皇十十十十十十
十十十皇十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十十十皇
十十十十十皇十十
皇十十十十十十十

十十十十皇十十十
十皇十十十十十十
十十十十十皇十十
皇十十十十十十十
十十十十十十皇十
十十十皇十十十十
十十十十十十十皇
十十皇十十十十十

十十十十皇十十十
十皇十十十十十十
十十十十十十十皇
皇十十十十十十十
十十十皇十十十十
十十十十十十皇十
十十皇十十十十十
十十十十十皇十十

十十十十皇十十十
十十皇十十十十十
皇十十十十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十
十十十十十十皇十

十十十十皇十十十
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
十十十皇十十十十

十十十十皇十十十
十十皇十十十十十
十十十十十十十皇
十十十皇十十十十
十十十十十十皇十
皇十十十十十十十
十十十十十皇十十
十皇十十十十十十

十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十十十十皇
十十十十十皇十十
十十十皇十十十十
十皇十十十十十十

十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
十十皇十十十十十

十十十十皇十十十
十十十十十十皇十
十皇十十十十十十
十十十皇十十十十
十十十十十十十皇
皇十十十十十十十
十十皇十十十十十
十十十十十皇十十

十十十十皇十十十
十十十十十十皇十
十皇十十十十十十
十十十十十皇十十
十十皇十十十十十
皇十十十十十十十
十十十皇十十十十
十十十十十十十皇

十十十十皇十十十
十十十十十十皇十
十皇十十十十十十
十十十十十皇十十
十十皇十十十十十
皇十十十十十十十
十十十十十十十皇
十十十皇十十十十

十十十十皇十十十
十十十十十十皇十
十十十皇十十十十
皇十十十十十十十
十十皇十十十十十
十十十十十十十皇
十十十十十皇十十
十皇十十十十十十

十十十十皇十十十
十十十十十十十皇
十十十皇十十十十
皇十十十十十十十
十十皇十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十十十皇十

十十十十皇十十十
十十十十十十十皇
十十十皇十十十十
皇十十十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十皇十十
十十皇十十十十十

十十十十十皇十十
皇十十十十十十十
十十十十皇十十十
十皇十十十十十十
十十十十十十十皇
十十皇十十十十十
十十十十十十皇十
十十十皇十十十十

十十十十十皇十十
十皇十十十十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十皇十十十
十十十十十十十皇
十十十皇十十十十

十十十十十皇十十
十皇十十十十十十
十十十十十十皇十
皇十十十十十十十
十十十皇十十十十
十十十十十十十皇
十十十十皇十十十
十十皇十十十十十

十十十十十皇十十
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十

十十十十十皇十十
十十皇十十十十十
皇十十十十十十十
十十十十十十十皇
十十十皇十十十十
十皇十十十十十十
十十十十十十皇十
十十十十皇十十十

十十十十十皇十十
十十皇十十十十十
皇十十十十十十十
十十十十十十十皇
十十十十皇十十十
十皇十十十十十十
十十十皇十十十十
十十十十十十皇十

十十十十十皇十十
十十皇十十十十十
十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十十皇十十十十
十皇十十十十十十
十十十十十十十皇

十十十十十皇十十
十十皇十十十十十
十十十十皇十十十
十十十十十十十皇
皇十十十十十十十
十十十皇十十十十
十皇十十十十十十
十十十十十十皇十

十十十十十皇十十
十十皇十十十十十
十十十十十十皇十
十皇十十十十十十
十十十皇十十十十
十十十十十十十皇
皇十十十十十十十
十十十十皇十十十

十十十十十皇十十
十十皇十十十十十
十十十十十十皇十
十皇十十十十十十
十十十十十十十皇
十十十十皇十十十
皇十十十十十十十
十十十皇十十十十

十十十十十皇十十
十十皇十十十十十
十十十十十十皇十
十十十皇十十十十
皇十十十十十十十
十十十十十十十皇
十皇十十十十十十
十十十十皇十十十

十十十十十皇十十
十十十皇十十十十
皇十十十十十十十
十十十十皇十十十
十十十十十十十皇
十皇十十十十十十
十十十十十十皇十
十十皇十十十十十

十十十十十皇十十
十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十皇十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十

十十十十十皇十十
十十十皇十十十十
十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十皇十十十
十皇十十十十十十
十十十十十十十皇

十十十十十皇十十
十十十皇十十十十
十十十十十十皇十
皇十十十十十十十
十十十十十十十皇
十皇十十十十十十
十十十十皇十十十
十十皇十十十十十

十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十
十十皇十十十十十

十十十十十十皇十
皇十十十十十十十
十十皇十十十十十
十十十十十十十皇
十十十十十皇十十
十十十皇十十十十
十皇十十十十十十
十十十十皇十十十

十十十十十十皇十
十皇十十十十十十
十十十皇十十十十
皇十十十十十十十
十十十十十十十皇
十十十十皇十十十
十十皇十十十十十
十十十十十皇十十

十十十十十十皇十
十皇十十十十十十
十十十十十皇十十
十十皇十十十十十
皇十十十十十十十
十十十皇十十十十
十十十十十十十皇
十十十十皇十十十

十十十十十十皇十
十十皇十十十十十
皇十十十十十十十
十十十十十皇十十
十十十十十十十皇
十十十十皇十十十
十皇十十十十十十
十十十皇十十十十

十十十十十十皇十
十十皇十十十十十
十十十十十十十皇
十皇十十十十十十
十十十十皇十十十
皇十十十十十十十
十十十十十皇十十
十十十皇十十十十

十十十十十十皇十
十十十皇十十十十
十皇十十十十十十
十十十十皇十十十
十十十十十十十皇
皇十十十十十十十
十十皇十十十十十
十十十十十皇十十

十十十十十十皇十
十十十皇十十十十
十皇十十十十十十
十十十十十十十皇
十十十十十皇十十
皇十十十十十十十
十十皇十十十十十
十十十十皇十十十

十十十十十十皇十
十十十十皇十十十
十十皇十十十十十
皇十十十十十十十
十十十十十皇十十
十十十十十十十皇
十皇十十十十十十
十十十皇十十十十

十十十十十十十皇
十皇十十十十十十
十十十皇十十十十
皇十十十十十十十
十十十十十十皇十
十十十十皇十十十
十十皇十十十十十
十十十十十皇十十

十十十十十十十皇
十皇十十十十十十
十十十十皇十十十
十十皇十十十十十
皇十十十十十十十
十十十十十十皇十
十十十皇十十十十
十十十十十皇十十

十十十十十十十皇
十十皇十十十十十
皇十十十十十十十
十十十十十皇十十
十皇十十十十十十
十十十十皇十十十
十十十十十十皇十
十十十皇十十十十

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