八皇后问题

八皇后问题

1. 八皇后问题介绍

八皇后问题是一个经典的回溯算法思想求解的问题,该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出的:在8×8的国际象棋棋盘上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,求共有多少种摆法。

八皇后问题.png

2. 回溯算法求解八皇后问题的思路

  • 第一个皇后先放在第一行第一列;
  • 第二个皇后放在第二行第一列,先判断是否冲突,若冲突,则继续往后放,依次把所有列都放完,找到合适的位置;
  • 继续按照上一个步骤放置其余的皇后,直至8个皇后都放置在互不冲突的位置,(此过程中可能发生回溯到步骤二),即找到了一个正确解;
  • 当得到一个正确解时,退回到上一个栈,开始回溯,将第一个皇后放在第一列的所有正确解求出(即第一个皇后仍放在第一列不变,其他皇后继续往后摆);
  • 然后回头继续第一个皇后放第一行第二列,继续执行上述步骤。

说明:

  • 理论上应该创建一个二维数组来表示棋盘,但实际上可以通过算法,用一个一维数组即可解决问题:arr[8] = {0, 4, 7, 5, 2, 6, 1, 3}
  • arr数组的下标表示皇后所在的行(也即第n+1个皇后),arr数组的值表示皇后所在的列
  • eg.arr[3] = 5就表示第4个皇后在第4行第6列

函数解释:

judge(int n)方法:

  • 用于判断当前放置的第n+1个皇后是否与前面放置的所有皇后冲突
  • 判断是否在同一列:arr[i] == arr[n]
  • 判断是否在同一斜线:Math.abs(i - n) == Math.abs(arr[i] - arr[n])
  • 通过判断斜率是否为1判断是否在同一斜线上,即行差的绝对值是否等于列差的绝对值

check(int n)方法:

  • 用于放置当前的第n+1个皇后(n从0开始计数,因此当n == 8时,已经准备放置第9个皇后,即前8个皇后已经正确放置,退出程序即可)
  • 每一个当前放置的皇后都需要放置到该行的每一列并与前面放置的皇后进行judge,因此需要一个for循环,若不冲突才放置下一个
  • 进一步地,上步放置下一个皇后时即开始了递归过程,每一次check都经历一个for循环。当某一次放置的for循环走完时仍冲突,即回退到了上一个栈,继续执行上一次放置时的for循环(即i++往后面的列摆),即完成回溯的过程

3. 代码实现

package com.algorithm;

/**
 * @author SnkrGao
 * @create 2023-04-08 22:11
 */
public class EightQueens {

    int queenNum = 8;
    int[] arr = new int[queenNum];
    static int count = 0;

    public static void main(String[] args) {
        EightQueens eightQueens = new EightQueens();
        eightQueens.check(0);
        System.out.println("共有"+count+"种解法");

    }

    // 放置第n+1个皇后
    // 需要注意每一次check递归时,都会执行for循环,因此会产生回溯
    private void check(int n) {
        if (n == queenNum) { // 递归终止条件,表示前8个皇后都放置完成,即退出程序
            print();
            return;
        }
        for (int i = 0; i < queenNum; i++) { // 此处i < 8表示放置在每一行的不同列
            // 循环开始时先将第n+1个皇后放置在第一列的位置
            arr[n] = i;
            // 判断第n+1个皇后放置在i列时与前面所有皇后是否冲突
            if (judge(n)) {
                // 若不冲突开始放置下一个皇后,即开始递归
                check(n + 1);
            }
            // 若冲突,则继续执行arr[n] = i++,将该皇后往后摆一列
        }
    }

    // 判断当前放置的第n+1个皇后是否与前面的皇后位置冲突
    private boolean judge(int n) {
        for (int i = 0; i < n; i++) {
            if (arr[i] == arr[n] || Math.abs(n - i) == Math.abs(arr[n] - arr[i])) {
                return false;
            }
        }
        return true;
    }

    // 输出arr数组,即皇后摆放位置的每一种解法
    private void print() {
        count++;
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
        }
        System.out.println();
    }
}
posted @   GaoakaJie  阅读(248)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示