1 八皇后问题

news2024/11/15 12:19:57

算法

  八皇后问题是在国际象棋的棋盘上放八个皇后,八个皇后不能互相攻击。国际象棋的皇后,可以横向攻击也可以纵向攻击,也可以斜向攻击。所以要放八个皇后,就必须任一直线和斜线上不能同时有两个皇后。比如以下就是一个八皇后方案:
在这里插入图片描述

  解决八皇后问题的算法是回溯法,因为穷举法需要循环的次数太多,所以用回溯法。其基本思想如下:
  循环遍历行,在循环中:

  1. 如果成功,跳到下一行;
  2. 如果失败,回到上一行,寻找下一个位置
  3. 如果到了第一行最后一个位置,那么就失败了。

代码

  代码如下:

public static final int SIZE = 8;

public static void main(String[] args) {
    // 用一个数组来显示
    final int[] ints = {-1, -1, -1, -1, -1, -1, -1, -1};
    int r = 0;
    for (;r >=0 && r < SIZE; ) {
        int column = findPosition(ints, r);
        // 找不到
        if (column < 0) {
            ints[r] = -1;
            r--;
        } else {
            ints[r] = column;
            r++;
        }
    }
    final Chessboard chessboard = new Chessboard(ints);
    System.out.println(chessboard);
}

/**
 * 找第row行的合法位置
 * @param ints
 * @param row
 * @return
 */
private static int findPosition(int[] ints, int row) {
    // begin at next column
    final int column = ints[row] + 1;
    for (int c = column; c < SIZE; c++) {
        if (valid(ints, row, c)) {
            return c;
        }
    }
    return -1;
}

private static boolean valid(int[] ints,int row, int c) {
    // 在第几行上
    // 循环啊
    for (int i = 0; i < row; i++) {
        // 如果同一列
        final int otherC = ints[i];
        if (otherC == c) {
            return false;
        }
        // 如果是斜对角,比如对方是 r0 c2 我是 r1 c3
        // 或者我是r1 c1 row - i 是行数差  other c - c 为列数差
        if (row - i == Math.abs(otherC - c)) {
            return false;
        }
    }
    return true;
}

  那么如何计算出所有的八皇后方案呢?上面的代码是不行的,只能找到一种方案,要找到所有的方案就必须修改算法了。

所有方案算法

  如果要遍历所有的方案,很明显可以看出这是个树形结构,前N行构成一种方案,但是在N+1行时可能就有不止一种方案了,这样就形成了分支,所以整个方案就构成了一个树形结构了。所以先简单做一个树形结构,再对这个树形结构进行回溯法搜索。
  我用穷举法实现了,总共92种解法。首先是树的代码:

package com.trend;

import java.util.ArrayList;
import java.util.Collections;

/**
 * 方案树
 *
 * @author a simple coder
 * @since 1.0.0
 * created in 2023/5/31, 星期三
 */
public class SolutionTree {

    private Node root;

    public SolutionTree(int i) {
        Node node = new Node();
        node.setRow(0);
        node.setColumn(i);
        root = node;

    }

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

    public static class Node {

        private int column;
        private int row;
        private Node[] children;

        private Node parent;

        public int getColumn() {
            return column;
        }

        public void setColumn(int column) {
            this.column = column;
        }

        public int getRow() {
            return row;
        }

        public void setRow(int row) {
            this.row = row;
        }

        public Node[] getChildren() {
            return children;
        }

        public void setChildren(Node[] children) {
            this.children = children;
            for (Node node:children) {
                node.parent = this;
            }
        }

        public Node getParent() {
            return parent;
        }

        public void setParent(Node parent) {
            this.parent = parent;
        }

        public void remove(Node pop) {
            ArrayList<Node> nodes = new ArrayList<>();
            for (Node node: children) {
                if (node != pop) {
                    nodes.add(node);
                } else {
                    node.parent = null;
                }
            }
            this.children = nodes.toArray(new Node[0]);
        }

        @Override
        public String toString() {
            return "Node{" +
                    "column=" + column +
                    ", row=" + row +
                    '}';
        }

        public String path() {
            StringBuilder stringBuilder = new StringBuilder();
            for (SolutionTree.Node start = this; start != null; start = start.getParent()) {
                stringBuilder.append(start.column).append(">-");
            }
            return stringBuilder.reverse().toString();
        }

        public String latex(int size) {

            ArrayList<String> strings = new ArrayList<>();
            int i=size;
            for (SolutionTree.Node start = this; start != null; start = start.getParent()) {
                strings.add("Q"+(char)('a'+start.column)+(i--)+"");
            }
            Collections.reverse(strings);
            String x = String.join(",", strings);
            return  "\\chessboard[\n" +
                    "\tstyle=8x8,\n" +
                    "\tsetpieces={"+x+"},\n" +
                    "\tpadding=1ex,\n" +
                    "\t]";
        }
    }
}

  然后是逻辑代码:

package com.trend;

import java.util.*;

/**
 * 八皇后
 *
 * @author a simple coder
 * @since 1.0.0
 * created in 2023/5/31, 星期三
 */
public class EightQueens {

    public static final int SIZE = 8;

    public static void main(String[] args) {
        // 用一个数组来显示
        // 初始化8种方案
        int size = 0;
        for (int i = 0; i < SIZE; i++) {
            SolutionTree solutionTree = getSolutionTree(i);

            ArrayDeque<SolutionTree.Node> nodes = new ArrayDeque<>();
            nodes.add(solutionTree.getRoot());
            while (!nodes.isEmpty()) {
                SolutionTree.Node pop = nodes.pop();
                SolutionTree.Node[] children = pop.getChildren();
                if (children != null) for (SolutionTree.Node n : children) {
                    nodes.add(n);
                }
                if (pop.getRow() == SIZE - 1) {
                    System.out.println(pop.latex(SIZE));
                    size++;
                }
            }
        }
        System.out.println(size);

    }

    private static SolutionTree getSolutionTree(int start) {
        SolutionTree solutionTree = new SolutionTree(start);
        SolutionTree.Node root = solutionTree.getRoot();
        ArrayDeque<SolutionTree.Node> nodes = new ArrayDeque<>();
        nodes.add(root);
        while (!nodes.isEmpty()) {
            SolutionTree.Node pop = nodes.pop();
            List<Integer> positions = findPositions(pop);
            if (pop.getRow() == SIZE - 1) {
                continue;
            }
            if (positions.isEmpty()) {
                // 删除当前节点
                if (pop.getParent() != null) pop.getParent().remove(pop);
            } else {
                SolutionTree.Node[] children = new SolutionTree.Node[positions.size()];
                int i = 0;
                for (int position : positions) {
                    SolutionTree.Node node = new SolutionTree.Node();
                    node.setRow(pop.getRow() + 1);
                    node.setColumn(position);
                    children[i++] = node;
                    nodes.push(node);
                }
                pop.setChildren(children);
            }
        }
        return solutionTree;
    }


    /**
     * 找第row行的合法位置
     *
     * @param node 解决方案树的节点
     * @return
     */
    private static List<Integer> findPositions(SolutionTree.Node node) {
        // 本节点的所在行
        ArrayList<Integer> integers = new ArrayList<>();
        // begin at next column
        final int column = 0;
        for (int c = column; c < SIZE; c++) {
            if (valid(node, c)) {
                integers.add(c);
            }
        }
        return integers;
    }

    /**
     * 验证是否有效
     *
     * @param node   结点
     * @param row    第几行
     * @param column 第几列
     * @return 是否有效
     */
    private static boolean valid(SolutionTree.Node node, int column) {
        // 在第几行上
        // 循环啊
        int row = node.getRow() + 1;
        for (SolutionTree.Node start = node; start != null; start = start.getParent()) {

            // 如果同一列
            final int otherC = start.getColumn();
            if (otherC == column) {
                return false;
            }

            // 如果是斜对角,比如对方是 r0 c2 我是 r1 c3
            // 或者我是r1 c1 row - i 是行数差  other c - c 为列数差
            if (row - start.getRow() == Math.abs(otherC - column)) {
                return false;
            }
        }
        return true;
    }


}

  最终结果里我取了四个,大概就是这样子:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/593595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

eslint的使用

为什么要使用eslint? ​ eslint可以帮助我们统一代码语法规范。 eslint官网: https://eslint.org/ 1.vscode中改缩进 ​ 设置->tabsize-> tab-size和vetur都改成2 ​ format->格式化->勾选format on save 2.Vscode安装Eslint插件 (1)配置Eslint插件 ​ 设…

Yandex:你不可错过的全能搜索引擎

目录 前言一、Yandex网站介绍1-1、网站介绍1-2、优势 二、Yandex网站使用技巧2-1、Yandex搜索引擎2-2、Yandex Maps2-3、Yandex Mail2-4、Yandex Games2-5、Yandex Images2-6、Yandex Video2-7、Yandex.Translate 结语 前言 andex是一家俄罗斯的互联网公司&#xff0c;成立于19…

【HarmonyOS】元服务和APP的相互跳转、相互成就

【关键字】 卡片、跳转、加桌 【背景介绍】 随着鸿蒙生态的发展&#xff0c;各种类型的应用都已经可以在Harmony OS上无差异的运行&#xff0c;面对鸿蒙新兴元服务的兴起&#xff0c;各大厂家可能都在考虑一个问题&#xff1a;如果已经有APP了&#xff0c;有必要再开发一款元…

用 JavaScript 对抗 DDOS 攻击 (下)

抗 v2 之前的那些奇技淫巧&#xff0c;纯属娱乐而已&#xff0c;并不能撑多久。 但简单、好玩&#xff0c;似乎这正是对抗的乐趣。之前从未想过&#xff0c;居然还能把脚本黑科技&#xff0c;用在网络防御上。 于是&#xff0c;又陆陆续续对抗了一段时间。 直到兴致淡却&am…

WordPress 网站管家小程序源码

正文&#xff1a; Wordpress网站管家小程序源码&#xff0c;基于uniapp开发的产品&#xff0c;WP管家是主打用户访问端&#xff0c;兼容了微信小程序与安卓APP&#xff08;其他端未测试&#xff09;&#xff0c;用于用户的访问。 1、在Wordpress根目录新建一个文件夹&#xf…

达美乐的面试(部分)(未完全解析)

Java如何保证非线程安全的数据结构&#xff08;比如HashMap&#xff09;的原子性&#xff1f;读多写少时用哪种锁好? A: 方法1&#xff1a;CAS等乐观锁机制&#xff0c;方法2&#xff1a;如果读多写少&#xff0c;可以使用读写锁&#xff08;ReentrantReadWriteLock&#xff0…

在Centos Stream 9上Docker的实操教程(二) - Docker的常用命令

在Centos Stream 9上Docker的实操教程 - Docker的常用命令 Docker启动类命令Docker镜像命令镜像列表 docker images镜像查找 docker search拉取镜像 docker pull删除镜像 docker rmi查看占用信息 docker system df容器创建新镜像 docker commit 容器命令启动容器 docker run查看…

vue组件化路由

文章目录 vue项目1.vue组件2.插槽3.自定义指令4.vue路由 vue项目 vue项目中src目录的构成 assets: 存放项目中用到的静态资源文件,例如css,图片资源等components: 存放我们封装的、可复用的组件main.js: 项目的入口文件,整个项目的运行要先执行main.jsApp.vue: 项目的根组件 …

定时器详解 -- 定时器中断、PWM输出 --stm32

STM32定时器使用 STM32定时器计数模式定时器工作原理基本定时器&#xff1a;TIM6、TIM7示例代码代码讲解 通用定时器&#xff1a;TIM2、TIM3、TIM4、TIM5高级定时器&#xff1a;TIM1、TIM8定时器PWM输出原理通用定时器3控制通道1输出PWM脉冲代码 总结参考资料 STM32定时器 STM…

加密与解密 调试篇 动态调试技术 (三)-OllyDbg 插件 Run/Hit 符号调试 加载程序

目录 插件 这里给出一个命令行插件 Run Trace 运行 Hit Trace 符号调试 符号格式 1.SYM格式 2.COFF格式 3.CodeView格式 4.PDB格式 5.DBG格式 6.MAP文件 创建调试文件 加载程序 1.CreateProcess 2.将OllyDbg附加到一个正在运行的程序上 插件 OllyDbg允许插件 …

1计算机网络体系结构_1.1计算机网络概述

1.1.1计网_概念 概念&#xff1a; 计网是一个 将【分散的、具有独立功能的】计算机系统&#xff0c;通过【通信设备与线路】连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。简言之&#xff0c;计算机网络就是一些 互连的、自治的 计算机系统 的 集合。 …

excel函数采集,截取特殊符号前面/后面数据

截取前面 LEFT(I2,FIND("-",I2)-1) 截取后面 MID(I2,FIND("-",I2)1,99) 房贷利率计算公司&#xff0c;等额本金 (B2-G2*A2)*F2*0.01 Excel常用电子表格公式大全  一、Excel基本公式   1、查找重复内容公式&#xff1a;IF(COUNTIF(A:A,A2)>1,&qu…

国密算法解析

国密算法即国家密码局认定的国产密码算法。 国密算法是商用密码&#xff0c;仅能用于商业用途。国密算法是一套标准&#xff0c;由国家密码局制定的规范&#xff0c;凡是符合的&#xff0c;都可以称之为国密算法。国密算法暂无官方的代码实现&#xff0c;企业可以自己编码实现…

2022年五一杯数学建模A题血管机器人的订购与生物学习解题全过程及论文和程序

2022年五一杯数学建模A题 血管机器人的订购与生物学习 原题再现&#xff1a; 随着微机电系统的发展&#xff0c;人类已经可以加工越来越小的机器。这些机器小到一定程度就可以放进血管开展疾病治疗&#xff0c;这就是血管机器人。血管机器人可以携带药物放入血管里定点治疗与…

信号调制的工作原理

要理解如何进行无线数据传输&#xff0c;我们需要了解&#xff1a; 什么是频率&#xff1f; 信息/数据信号 时间表示 频率表示&#xff0c;为什么它很重要&#xff1f; 滤波器如何工作&#xff1f; FCC通信频段 调制和解调 这些主题可能您在大学专业课上学过&#xff0c…

uboot下的mw写内存和md显示内存命令以及nand命令

配置uboot参数 setenv ipaddr 192.168.0.10;setenv serverip 192.168.0.40;setenv gatewayip 192.168.0.1;setenv netmask 255.255.255.0 setenv bootargs mem512M consolettyAMA0,115200 root/dev/mtdblock2 rootfstypeyaffs2 rw init/init mtdpartshinand:1M(boot),4M(kern…

面试offer收割机,爆肝整理高频软件测试面试题(带答案)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件测试面试题&am…

excel 给合并的单元格进行序号填充

一、问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 在使用excel 的时候&#xff0c;是否遇到过要给合并单元格排序的情况&#xff0c;下拉会显示需要相同的单元格才行&#xff0c;如图&#xff1a; 二、解决方案 目的是给单元格计数&#xff0c;所以使用…

Module not found: Error: Can‘t resolve ‘fs‘ in ‘/root/workspace/

项目发版时 因为webpack5 不会自动引入polyfills 导致报了一系列错&#xff0c; 按照提示做如下配置 externals 官网文档解释的很清楚&#xff0c;就是webpack可以不处理应用的某些依赖库&#xff0c;使用externals配置后&#xff0c;依旧可以在代码中通过CMD、AMD或者wi…

打车/代驾/跑腿小程序源码司机入住uniapp/thinkphp

开发代驾顺风车货运 客户端&#xff1a;Uniapp 开发 司机端&#xff1a;Uniapp 开发 后台&#xff1a;thinkphp5 框架 数据库&#xff1a;MySQL 打车/代驾/跑腿小程序源码司机入住uniapp/thinkphp 为什么用UNIAPP开发&#xff1f; UNIAPP框架简单&#xff0c;学习成本低…