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

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

题目介绍

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际象棋棋手马克斯·贝瑟尔于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


相关文章
|
5月前
|
机器学习/深度学习 算法 Java
基于灰狼优化算法(GWO)解决柔性作业车间调度问题(Matlab代码实现)
基于灰狼优化算法(GWO)解决柔性作业车间调度问题(Matlab代码实现)
343 1
|
5月前
|
供应链 算法 Java
【柔性作业车间调度问题FJSP】基于非支配排序的多目标小龙虾优化算法求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
【柔性作业车间调度问题FJSP】基于非支配排序的多目标小龙虾优化算法求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
213 1
|
5月前
|
供应链 算法 调度
基于非支配吸血水蛭优化算法 (NSBSLO)求解多目标柔性作业车间调度问题(FJSP)研究(Matlab代码实现)
基于非支配吸血水蛭优化算法 (NSBSLO)求解多目标柔性作业车间调度问题(FJSP)研究(Matlab代码实现)
154 8
|
5月前
|
机器学习/深度学习 负载均衡 算法
【柔性作业车间调度】基于四种多目标优化算法(NSOOA、NSPSO、NSDBO、NSCOA)求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
【柔性作业车间调度】基于四种多目标优化算法(NSOOA、NSPSO、NSDBO、NSCOA)求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
326 0
|
11月前
|
算法 数据可视化 调度
基于NSGAII的的柔性作业调度优化算法MATLAB仿真,仿真输出甘特图
本程序基于NSGA-II算法实现柔性作业调度优化,适用于多目标优化场景(如最小化完工时间、延期、机器负载及能耗)。核心代码完成任务分配与甘特图绘制,支持MATLAB 2022A运行。算法通过初始化种群、遗传操作和选择策略迭代优化调度方案,最终输出包含完工时间、延期、机器负载和能耗等关键指标的可视化结果,为制造业生产计划提供科学依据。
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
机器学习/深度学习 算法 数据处理
EM算法对人脸数据降维(机器学习作业06)
本文介绍了使用EM算法对人脸数据进行降维的机器学习作业。首先通过加载ORL人脸数据库,然后分别应用SVD_PCA、MLE_PCA及EM_PCA三种方法实现数据降维,并输出降维后的数据形状。此作业展示了不同PCA变种在人脸数据处理中的应用效果。
140 0
|
4月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
464 0
|
4月前
|
数据采集 分布式计算 并行计算
mRMR算法实现特征选择-MATLAB
mRMR算法实现特征选择-MATLAB
316 2
|
5月前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
297 3

热门文章

最新文章