数据结构与算法-- 八皇后问题(多种实现方案)

八皇后问题解法一(排列筛选法)

  • 本篇我们承接上一篇中的思想,想到了一个经典的算法题,八皇后问题:
  • 题目:在8*8的国际象棋上摆放8个皇后,使得其互相不能攻击,即任意两个换后不能在同一行,同一列,或者同一对角线上。如下图中所示,就是一个符合预期的摆放方式,问总共有多少中摆放方式。

在这里插入图片描述

  • 上图中的数字代表此处放置一个皇后,并且从上到下依次是0~7 总共8个。

  • 分析:

    • 由于8个皇后任意两个不能处在同一行,那么肯定每个皇后占据一行。
    • 有上图看,我们必然可以用数组来标识myQueen[8] 数组,数组中i 个数字表示位于第i 行的皇后
    • 例如以上图为案例可以用数组 myQueen[8] = {4,2,0,5,7,1,3,6} 来标识这种摆放的可能,
      • 就是我们直接用数组下标当成皇后所在的列
      • 用数组的下标对应的值当成皇后所在的行
    • 那么现在我们的思路就是求出 myQueen数组的全排列,接着在筛选出符合要求的
    • 符合要求的情况:
      • 我们依据以上思路得到的全排列,天然就不会再同一行,也不会在同一列
      • 只需要筛选左右对角线上是否有其他数据,那么只需要对比下标 i 和 j的差值与 i和j 下标对应的value的差值是否相等
      • i - j == myQueen[i] -myQueen[j] || j-i == myQueen[i] - myQueen[j]
      • 以上判断可以用具体案例来验证此处略。
  • 依据如上分析有如下代码:

/***  八皇后问题* @author liaojiamin* @Date:Created in 15:03 2021/5/26*/
public class EightQueen {private static final List<Integer[]> myQueen = new ArrayList<>();public static void main(String[] args) {Integer[] eight = {0,1,2,3,4,5,6,7};getEightQueenPerMutain(eight, 0);List<Integer[]> realQueen = checkQueen(myQueen);for (Integer[] integers : realQueen) {for (int i = 0; i < integers.length; i++) {System.out.print(integers[i]+",");}System.out.println();}}/*** 检查所有可能的八皇后排列,筛选出符合条件的:* i-j == integer[i] - integer[j] || j-i = integer[i]-integer[j] 情况的都是统一对角的* */public static List<Integer[]> checkQueen(List<Integer[]> myQueen){List<Integer[]> realEightQueen = new ArrayList<>();for (Integer[] integers : myQueen) {boolean isCheck = true;for (int i = 0; i < integers.length; i++) {if(!isCheck){break;}for (int j = i+1; j<integers.length;j++){if((i-j) == (integers[i] - integers[j])|| (j-i) == (integers[i] - integers[j])){isCheck = false;break;}}}if(isCheck){realEightQueen.add(integers);}}return realEightQueen;}/*** 八皇后问题排列解决方案* */public static void getEightQueenPerMutain(Integer[] eight, Integer start){if(eight == null || eight.length <= 1 || start == eight.length-1){Integer[] newEight = new Integer[eight.length];for (int i = 0; i < eight.length; i++) {newEight[i] = eight[i];}myQueen.add(newEight);}for (int i = start; i <= eight.length-1; i++) {Integer temp = eight[start];eight[start] = eight[i];eight[i] = temp;getEightQueenPerMutain(eight, start+1);temp = eight[start];eight[start] = eight[i];eight[i] = temp;}}
}

八皇后问题解法二(动态规划)

  • 接上文中,依然可以用数组 myQueen[8] = {4,2,0,5,7,1,3,6} 来标识这种摆放的可能

  • 那么上文中将所有排列列举出来后在对排列集合进行筛选得到最终的八皇后集合

  • 类似的思路,我们用穷举法将数组myQueen中包含0 ~ 7 的所有数字的可能一一列举,并且实时筛选,这样我们可以一个步骤直接得到想要的集合

  • 经过如上分析有如下代码:

/***  八皇后问题* @author liaojiamin* @Date:Created in 15:03 2021/5/26*/
public class EightQueen {private static final List<Integer[]> myQueen = new ArrayList<>();public static void main(String[] args) {for (int i = 0; i < 8; i++) {Integer[] eight = new Integer[8];getEightQueen(eight, i);}for (Integer[] integers : myQueen) {for (int i = 0; i < integers.length; i++) {System.out.print(integers[i] + ",");}System.out.println();}System.out.println(myQueen.size());}/*** 穷举+筛选* 直接获取八皇后问题最终结果* */public static void getEightQueen(Integer[] queen, int start){for (int i = 0; i < 8; i++) {queen[start] = i;if(checkout(queen, start)){if(start == queen.length -1){Integer[] realQueen = new Integer[8];for (int i1 = 0; i1 < queen.length; i1++) {realQueen[i1] = queen[i1];}myQueen.add(realQueen);}else {getEightQueen(queen, start + 1);}}}}/**
* 校验是否符合八皇后问题规则
*/public static boolean checkout(Integer[] queen, Integer end){Set<Integer> checkRepeat = new HashSet<>();for (int i = 0; i <= end; i++) {if(checkRepeat.contains(queen[i])){return false;}checkRepeat.add(queen[i]);for(int j = i+1; j<= end; j++){if(queen[i] == null || queen[j] == null){return false;}if((i-j) == (queen[i]- queen[j]) || (j-i) == (queen[i] - queen[j])){return false;}}}return true;}
}

八皇后问题解法三(回朔递归)

  • 依然可以用数组 myQueen[8] = {4,2,0,5,7,1,3,6} 来标识这种摆放的可能
  • 首先将第一个皇后放入第一列位置
  • 接着将第二个皇后分别放入第二三四等之后的位置,每次分别去检查放入的位置是否与之前的位置中放入的皇后是否在同一列,同一对角线
  • 接着依次对地三个,第四个,直到第八个皇后重复第二步骤,找出每个皇后所有合法的位置
  • 方法三 与方法二的实现方式非常类似,区别在于筛选,方法三种的筛选只需要对比最后一个元素与之前的元素是否冲突,在方法三中是每个皇后的位置依次检查,当进行到第5个皇后的时候,能保证前4个皇后的位置都是合法的,无需在检查之前的。
  • 具体实现方案如下,方法三实现方案更好理解。
/*** 八皇后问题** @author liaojiamin* @Date:Created in 15:03 2021/5/26*/
public class EightQueen {private static final List<Integer[]> myQueen = new ArrayList<>();public static void main(String[] args) {getEightQueenRetro();print();}public static void print() {for (Integer[] integers : myQueen) {for (int i = 0; i < integers.length; i++) {System.out.print(integers[i] + ",");}System.out.println();}System.out.println(myQueen.size());}/*** 回朔递归*/public static void getEightQueenRetro() {Integer[] eight = new Integer[8];check(eight, 0);}//递归回朔便利每一种可能public static void check(Integer[] eight, int n) {if (n == eight.length) {myQueen.add(Arrays.copyOf(eight, eight.length));return;}for (int i = 0; i < eight.length; i++) {eight[n] = i;if(judge(eight, n)){check(eight, n+1);}}}//筛选public static boolean judge(Integer[] eight, int n){for(int i=0;i<n;i++){if(eight[i] == eight[n] || Math.abs(n-i) == Math.abs(eight[n] - eight[i])){return false;}}return true;}
}

总结

  • 以上两个方法的整体思路类似,当题目需要我们按照一定规则摆放若干个数字的时候,我们可以先求出这些数字的所有可能,然后在一一判断每个组合是否满足题目给定的要求。
  • 方法一利用上一篇中的排列的算法得出所有排列可能,接着筛选,时间复杂度O( n3 )
  • 方法二 利用递归穷举方法得出所有数字的可能,并同时筛选,时间复杂度也是O(n3)
  • 两种算法的时间复杂度都并非很优,如有更好的算法思想,求在评论指出

上一篇:数据结构与算法–字符串的排列组合问题
下一篇:数据结构与算法-- 数组中出现次数超过一半的数字(时间复杂度的讨论)

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

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

相关文章

Blazor WebAssembly 3.2.0 正式起飞,blazor 适合你吗?

最近blazor更新很快&#xff0c;今天在官方博客上发布了Blazor WebAssembly 3.2.0 RC&#xff1a;https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-release-candidate-now-available/ &#xff0c;这是最后一次预览版了&#xff0c;功能开发都已经完成。5.19的…

中获取文件名不要扩展名_如何批量修改文件名,3s时间够不够

?点击关注Excel表哥公众号上一篇推文我们介绍了如何批量获取同一文件夹下所有的文件名。▲点此图片回顾很多读者获取到这些文件名之后的一种工作情形就是需要批量或者有针对性地修改这些文件的名称。那么但凡是这类需要批量操作的重复工作&#xff0c;Excel擅长。还是以上篇推…

数据结构与算法--死磕二叉树

死磕二叉树 近一年都比较关注算法相关的知识&#xff0c;也刷了不少题&#xff0c;之前的文章中大多也是算法相关的文章&#xff0c;但是感觉每次遇到树相关的题型都不能应对自如&#xff0c;因此还是有必要在相关知识上下功夫&#xff0c;因此有此次总结&#xff0c;以下是所…

Jenkins 中以构建 Tag 来实现版本管理

好的工具和流程能使我们事半功倍&#xff0c;而这个过程是不断迭代和演进的。关于这一块的内容&#xff0c;之前写过几篇文章&#xff1a;在团队中使用GitLab中的Merge Request工作模式敏捷下的需求和代码分支管理不断进化的分支和需求管理现在又有了些新的变化和改进&#xff…

将字符串添加负数_Go语言实现LeetCode算法:8 字符串转整数

Go语言中文网&#xff0c;致力于每日分享编码、开源等知识&#xff0c;欢迎关注我&#xff0c;会有意想不到的收获&#xff01;看到题目&#xff0c;是不是超级简单&#xff0c;用 strconv.Atoi 就可以了&#xff1f;题目当然不是这么简单的要求。1 题目描述实现atoi函数&#…

[Java基础]生产者和消费者模式概述与案例分析

代码如下: package BoxPack01;public class Box {private int milk;private boolean state false;public synchronized void put(int milk){if (state){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}this.milk milk;System.out.println("送奶…

毕业4年年薪200万是怎样的一种体验?

之前的一篇文章提到过自己毕业4年&#xff0c;年薪就超过了200万。最近有很多读者问我是怎么实现的&#xff0c;过程中有哪些经验可以分享。说实话&#xff0c;这个话题不太想写&#xff0c;毕竟有炫耀嫌疑。不过问的人多了&#xff0c;发现大家对这个话题还是很关心。另外&…

自动控制原理第二版王建辉_王建辉自动控制原理配套题库名校考研真题课后答案资料课后习题章节题库模拟试题...

王建辉《自动控制原理》配套题库【名校考研真题&#xff0b;课后习题&#xff0b;章节题库&#xff0b;模拟试题】第一部分 名校考研真题 第1章 自动控制系统的基本概念 第2章 自动控制系统的数学模型 第3章 自动控制系统的时域分析 第4章 根轨迹法 第5章 频率法 第…

FluentAspects -- 基于 Fluent API 的 Aop

FluentAspects -- 基于 Fluent API 的 AopIntro上次我们做了一个简单的 AOP 实现示例&#xff0c;但是实现起来主要是基于 Attribute 来做的&#xff0c;对于代码的侵入性太强&#xff0c;于是尝试实现基于 Fluent API 的方式来做 AOP 。抽象 InterceptorResolver原来获取方法执…

[Java网络编程基础]InetAddress的使用

代码如下: package InetAddressPack;import java.net.InetAddress; import java.net.UnknownHostException;public class InetAddressDemo {public static void main(String[] args) throws UnknownHostException { // InetAddress address InetAddress.getByName(&qu…

文件夹复制 覆盖_软网应用:U盘即插即复制

虽然现在网盘非常普及&#xff0c;但是对于一些重要文件的同步&#xff0c;很多朋友仍然在使用U盘进行同步。常规的方法是在A电脑将文件复制到U盘&#xff0c;然后在B电脑插入U盘&#xff0c;再将需要同步的文件复制到B电脑。这种操作不仅效率低&#xff0c;而且容易漏掉文件。…

面向接口编程,你考虑过性能吗?

大家在平时开发中大多都会遵循接口编程&#xff0c;这样就可以方便实现依赖注入也方便实现多态等各种小技巧&#xff0c;但这种是以牺牲性能为代价换取代码的灵活性&#xff0c;万物皆有阴阳&#xff0c;看你的应用场景进行取舍。一&#xff1a;背景1. 缘由在项目的性能改造中&…

[Java网络编程]UDP通信程序练习

代码如下: package UdpPracticePack;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;pub…

打造更好用的 EF 自动审计

打造更好用的 EF 自动审计Intro上次基于 EF Core 实现了一个自动审计的功能&#xff0c;详细可以参考 EF Core 数据变更自动审计设计&#xff0c;虽然说多数情况下可以适用&#xff0c;但是因为要显式继承于一个 AuditDbContextBase 或 AuditDbContext&#xff0c;所以对代码的…

[Java网络编程基础]UDP发送和接收数据

代码如下: package InetAddressPack;import java.io.IOException; import java.net.*; import java.nio.charset.StandardCharsets;public class SendDemo {public static void main(String[] args) throws IOException {DatagramSocket ds new DatagramSocket();byte[] bys …

从Copyright到Copyleft,聊聊版权与开源协议

4月26日是世界知识产权日&#xff0c;很多人或许会觉得这和软件开发没什么关系&#xff0c;但事实上&#xff0c;开源软件大多受到知识产权法中著作权法&#xff08;Copyright&#xff0c;也称版权&#xff09;的保护。开源软件虽说开放了源代码&#xff0c;但是用户在使用、修…

[Java网络编程基础]TCP发送和接收数据

代码如下: package ClientPack;import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;public class ClientDemo {public static void main(String[] args) throws IOExcept…

手机端适应_不轻易透露的超强技巧!详解iVX中怎样做设备自适应

"自适应网页设计"的概念2010年&#xff0c;Ethan Marcotte提出了"自适应网页设计"&#xff08;Responsive Web Design&#xff09;这个名词&#xff0c;指可以自动识别屏幕宽度、并做出相应调整的网页设计&#xff0c;自适应是为了解决如何才能在不同大小的…