【短学期算法作业】八皇后问题(回溯法)

简介: 【短学期算法作业】八皇后问题(回溯法)

题目介绍

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际象棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一对角线上,问有多少种摆法。高斯认为有76种方案。1854年柏林象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

Input

无输入数据

Output

输出所有解


题目思路

根据规则我们可以得出每行必有一个皇后,则找指定皇后时只需在当行遍历。

首先根据规则找到一个皇后,然后根据规则把棋盘上不能有皇后点全部标记,再在剩下的棋盘上找下一个没被标记的皇后,如果找不到则回溯。

回溯:这个操作需要在每一步结束时加个“快照”,以便于回溯


具体代码

package com.dreamchaser;
import java.util.Stack;
/**
 * 八皇后问题
 * 每行都肯定有一个皇后
 */
public class test4 {
    //维护一个当前正在处理的矩阵
    static int[][] finalCheckerBoard=new int[8][8];
    static Stack<Step> stack=new Stack<Step>();
    /**
     * 控制循环的开关
     */
    static boolean flag=true;
    public static void main(String[] args) {
        /**
         * 第n组解
         */
        int n=0;
        //初始值
        Spot spot=findOne(finalCheckerBoard,stack.size()+1);
        while (flag){
            Step step=new Step();
            if (spot!=null){
                //若找到则将这个点处理后的棋盘与原来棋盘合并,然后入栈
                int[][] c;
                c=handle(spot);
                finalCheckerBoard=merge(c,finalCheckerBoard);
                //赋值给step,相当于给当前步骤存档,以便回溯
                step.setSpot(spot);
                step.setCheckerboard(finalCheckerBoard);
                step.setNumber(stack.size()+1);
                //步骤入栈
                stack.push(step);
                spot=findOne(finalCheckerBoard,stack.size()+1);
                if (stack.size()==8){
                    Stack<Step> steps= (Stack<Step>) stack.clone();
                    n++;
                    System.out.println("第"+n+"组解:");
                    while (steps.size()>0){
                        System.out.println(steps.pop().spot);
                    }
                    recall();
                }
            }else{
                //若没找到,则回溯
                spot=recall();
            }
        }
    }
    /**
     * 回溯,返回上一步的下一个点,如果没有下一个点则放回null
     * @return 上一步的下一个点
     */
    private static Spot recall(){
            Step step=stack.pop();
            Spot spot=step.getSpot();
            if (spot.getY()<7){
                //处理finalCheckerBoard
                if (stack.isEmpty()){
                    //如果堆栈是空的话,则赋值一个初始值
                    finalCheckerBoard=new int[8][8];
                    for (int j=0;j<= spot.getY();j++){
                        finalCheckerBoard[spot.getX()][j]=1;
                    }
                }else {
                    //如果不为空,则直接从上一步中取值
                    finalCheckerBoard=stack.peek().getCheckerboard();
                    //因为之前没做过标记,这里回溯时前进一个防止重复
                    finalCheckerBoard[spot.getX()][spot.getY()]=1;
                }
                return findOne(finalCheckerBoard, step.getNumber());
            }
            if (stack.isEmpty()&&spot.getX()==0&&spot.getY()==7){
                flag=false;
            }
            //如果等于7,说明此皇后遍历完了,下一次得从上一个开始遍历
            return null;
    }
    /**
     * 在处理好的棋盘中找第number个皇后可以摆放的位置
     * @param handledcheckerboard 处理好的棋盘
     * @param number 第number个皇后
     * @return 摆放的位置
     */
    private static Spot findOne(int[][] handledcheckerboard,int number) {
        Spot spot=new Spot();
        int i=number-1;
        for (int j=0;j<8&&i<8;j++){
            if (handledcheckerboard[i][j]==0){
                spot.x=i;
                spot.y=j;
                return spot;
            }
        }
        return null;
    }
    /**
     * 处理棋盘
     * @param spot 皇后坐标
     * @return 处理好的棋盘
     */
    private static int[][] handle(Spot spot) {
        int x= spot.x;
        int y= spot.y;
        int[][] checkerboard=new int[8][8];
        for (int j=0;j<8;j++){
            checkerboard[x][j]=1;
        }
        for (int i = 0; i < 8; i++) {
            checkerboard[i][y]=1;
        }
        //处理对角线
        for (int i=0,j=y-x;i<8;i++,j++){
            if (j>=0&&j<8){
                checkerboard[i][j]=1;
            }
        }
        for (int i=0,j=x+y;i<8;i++,j--){
            if (j>=0&&j<8){
                checkerboard[i][j]=1;
            }
        }
        return checkerboard;
    }
    /**
     * 合并处理好的棋盘
     * @param checkerboards 处理好的棋盘
     * @return 合并好的棋盘
     */
    private static int[][] merge(int[][]...checkerboards) {
        int[][] checkerboard=new int[8][8];
        for (int[][] c:checkerboards){
            for (int i=0;i<8;i++){
                for (int j=0;j<8;j++){
                    if (c[i][j]==1){
                        checkerboard[i][j]=1;
                    }
                }
            }
        }
        return checkerboard;
    }
    /**
     * 记录点的坐标
     */
    private static class Spot{
        int x;
        int y;
        public Spot() {
        }
        public Spot(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public int getX() {
            return x;
        }
        public void setX(int x) {
            this.x = x;
        }
        public int getY() {
            return y;
        }
        public void setY(int y) {
            this.y = y;
        }
        @Override
        public String toString() {
            return "Spot{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    }
    /**
     * 记录每一步,便于存储和回溯
     */
    private static class Step{
        Spot spot;
        int[][] checkerboard;
        //记录序号
        int number;
        public Step() {
        }
        public Step(Spot spot, int[][] checkerboard, int number) {
            this.spot = spot;
            this.checkerboard = checkerboard;
            this.number = number;
        }
        public Spot getSpot() {
            return spot;
        }
        public void setSpot(Spot spot) {
            this.spot = spot;
        }
        public int[][] getCheckerboard() {
            return checkerboard;
        }
        public void setCheckerboard(int[][] checkerboard) {
            this.checkerboard = checkerboard;
        }
        public int getNumber() {
            return number;
        }
        public void setNumber(int number) {
            this.number = number;
        }
    }
}


运行截图


q1.png


相关文章
|
11天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
1月前
|
机器学习/深度学习 算法 数据处理
EM算法对人脸数据降维(机器学习作业06)
本文介绍了使用EM算法对人脸数据进行降维的机器学习作业。首先通过加载ORL人脸数据库,然后分别应用SVD_PCA、MLE_PCA及EM_PCA三种方法实现数据降维,并输出降维后的数据形状。此作业展示了不同PCA变种在人脸数据处理中的应用效果。
33 0
|
1月前
|
算法 定位技术
数据结构与算法学习九:学习递归。递归的经典实例:打印问题、阶乘问题、递归-迷宫问题、八皇后问题
本文详细介绍了递归的概念、重要规则、形式,并展示了递归在解决打印问题、阶乘问题、迷宫问题和八皇后问题等经典实例中的应用。
40 0
|
2月前
|
算法 调度
作业调度算法_先来先服务算法_短作业优先算法_高响应比优先算法
本文介绍了作业调度算法,包括先来先服务(FCFS)、短进程优先(SJF)和高响应比优先(HRRN)算法。通过分析进程的到达时间和所需CPU服务时间,计算进程的开始时间、完成时间、平均周转时间和平均带权周转时间,以评估不同算法的性能。FCFS适合长作业,SJF适合短作业,而HRRN则综合了两者的优点。
84 12
|
3月前
|
算法
算法设计与分析作业
这篇文章是关于算法设计与分析的作业,其中包含了两个算法实现:一个是使用分治算法实现的十进制大整数相乘(包括加法、减法和乘法函数),并进行了正确性和健壮性测试;另一个是使用快速排序思想实现的分治查找第K小元素的程序,并分析了其平均和最坏时间复杂度。
算法设计与分析作业
|
3月前
|
DataWorks 算法 调度
B端算法实践问题之配置脚本以支持blink批处理作业的调度如何解决
B端算法实践问题之配置脚本以支持blink批处理作业的调度如何解决
41 1
|
5月前
|
算法 Java C++
数据结构与算法===回溯法
数据结构与算法===回溯法
|
5月前
|
存储 机器学习/深度学习 算法
python 3种算法 回溯法、字典序生成、递归交换 实现全排列【力扣46题】
python 3种算法 回溯法、字典序生成、递归交换 实现全排列【力扣46题】
|
5月前
|
算法
数据结构和算法学习记录——栈和队列作业(实现链栈上的进栈、实现链栈上的退栈、实现链队上的入队列)
数据结构和算法学习记录——栈和队列作业(实现链栈上的进栈、实现链栈上的退栈、实现链队上的入队列)
27 0
|
25天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。