八皇后问题
来源:互联网 发布:阿里云盒子root 编辑:程序博客网 时间:2024/06/07 05:01
8皇后问题(java算法实现)
版权声明:本文为博主原创文章,未经博主允许不得转载。
最近总是无法静下心来集中精神干一些该干的事情,百般空虚之下,总得找了点有意义的东西填充一下,找了一道很久以前就听说挺经典的算法基础题来研究,就是下面那道题了,有一句话不知道怎么说来着,检验知识掌握与否的标准就在于你是否能把它清晰的传达出来。老实说,把整个思路写出来确实可以加深这个东西的理解。不过感觉现在的状态很欠揍,尽干这些东西来麻痹自己和打发时间。
八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。现代教学中,把八皇后问题当成一个经典递归算法例题。
—— 引用自百度百科
图1 国际象棋棋盘 图2 一种可行的8皇后摆放方案
首先,可归纳问题的条件为,8皇后之间需满足:
1.不在同一行上
2.不在同一列上
3.不在同一斜线上
4.不在同一反斜线上
这为我们提供一种遍历的思路,我们可以逐行或者逐列来进行可行摆放方案的遍历,每一行(或列)遍历出一个符合条件的位置,接着就到下一行或列遍历下一个棋子的合适位置,这种遍历思路可以保证我们遍历过程中有一个条件是绝对符合的——就是下一个棋子的摆放位置与前面的棋子不在同一行(或列)。接下来,我们只要判断当前位置是否还符合其他条件,如果符合,就遍历下一行(或列)所有位置,看看是否继续有符合条件的位置,以此类推,如果某一个行(或列)的所有位置都不合适,就返回上一行(或列)继续该行(或列)的其他位置遍历,当我们顺利遍历到最后一行(或列),且有符合条件的位置时,就是一个可行的8皇后摆放方案,累加一次八皇后可行方案的个数,然后继续遍历该行其他位置是否有合适的,如果没有,则返回上一行,遍历该行其他位置,依此下去。这样一个过程下来,我们就可以得出所有符合条件的8皇后摆放方案了。这是一个深度优先遍历的过程,同时也是经典的递归思路。
接下来,我们以逐列遍历,具体到代码,进一步说明。首先,从第一列开始找第一颗棋子的合适位置,我们知道,此时第一列的任何一个位置都是合适的,当棋子找到第一个合适的位置后,就开始到下一列考虑下一个合适的位置,此时,第二列的第一行及第二行显然就不能放第二颗棋子了,因为其与第一个棋子一个同在一行,一个同在一条斜线上。第二列第三行成为第二列第一个合适的位置,以此类推,第三列的第5行又会是一个合适位置,这个过程中,我们注意到,每一列的合适位置都是受到前面几列的位置所影响,归纳如下:
假设前面1列的棋子放在第3行,那当前列不能放的位置就一定是3行,2行,4行。因为如果放在这三行上就分别跟前一列的棋子同在一行、同在斜线、同在反斜线上,不符合我们的要求。现在我们用cols数组来表示8个列棋子所放的行数,数组下标从0开始,其中数组下标表示列数,数组的元素值表示该列棋子所在行数,当前列为N(N>=0,N<8),即cols[N-1]=3,则有:
cols[N] != cols[N-1](=3,表示不在同一行)
cols[N] != cols[N-1]-1(=3-1=2,表示不在同一斜线上)
cols[N]!=cols[N-1]+1(=3+1,表示不在同一反斜线上)
这里我们注意到,如果N-2列存在的话,那么我们还要考虑当前列N不与N-2列的棋子同行,同斜线,同反斜线。把当前列N的前面的某一列设为m,则m的所有取值为{m>=0,m<N}的集合,故又可在上面式子的基础,归纳为如下:
cols[N] != cols[m](与第m列的棋子不在同一行)
cols[N] != cols[m] -(N-m)(>=0 ,与第m列的棋子不在同一斜线上)
cols[N] != cols[m] + (N-m) (<=8-1,与第m列的棋子不在同一反斜线上)
具体到代码,很显然,取m的所有值只需要一句循环,同时我们为每一列定义一个长度为8的布尔数组row[],下标同样是从0开始,我们规定当row[i]=true时,表示该列第i行不能放棋子。这样我们就能写成下列程序段了:
- boolean[] rows = new boolean[8];
- for(int m=0;m<N;i++){
- rows[cols[m]]=true;//当前列N的棋子不能放在前面列m的棋子所在行。
- int d = N-m;
- //该句用于设置当前列N的棋子不能放在前面列m的棋子的斜线上
- if(cols-d >= 0)rows[cols-d]=true;
- // 该句用于设置当前列N的棋子不能放在前面列m的棋子的反斜线上
- if(cols+d <=8-1)rows[cols+d]=true;
- }
好了,到此为止,我们程序的核心内容都具备了,一个基于深度优先的遍历流程和一个判断位置是否合适的算法。下面贴出运行后算出的所有可行方案(即92种,“+”号代表空棋位,“0”代表皇后所在位置),源码(注源码变量名定义与上述略有不同,打印效果也不是图片所显示的效果,代码有做些微改动)。
package com.ctrip.langs.soa;/** * Created by kai_li on 2016/1/21. */public class Queen8 { public static int num = 0; //累计方案总数 public static final int MAXQUEEN = 8;//皇后个数,同时也是棋盘行列总数 public static int[] cols = new int[MAXQUEEN]; //定义cols数组,表示8列棋子摆放情况 public Queen8() { //核心函数 getArrangement(0); System.out.print("\n"); System.out.println(MAXQUEEN + "皇后问题有" + num + "种摆放方法。"); } public void getArrangement(int n) { //遍历该列所有不合法的行,并用rows数组记录,不合法即rows[i]=true boolean[] rows = new boolean[MAXQUEEN]; for (int i = 0; i < n; i++) { rows[cols[i]] = true; int d = n - i; if (cols[i] - d >= 0) { rows[cols[i] - d] = true; } if (cols[i] + d <= MAXQUEEN - 1) { rows[cols[i] + d] = true; } } for (int i = 0; i < MAXQUEEN; i++) { //判断该行是否合法 if (rows[i]) continue; //设置当前列合法棋子所在行数 cols[n] = i; //当前列不为最后一列时 if (n < MAXQUEEN - 1) { getArrangement(n + 1); } else { //累计方案个数 num++; //打印棋盘信息 printChessBoard(); } } } public void printChessBoard() { System.out.print("第" + num + "种走法 \n"); for (int i = 0; i < MAXQUEEN; i++) { for (int j = 0; j < MAXQUEEN; j++) { if (i == cols[j]) { System.out.print("0 "); } else System.out.print("+ "); } System.out.print("\n"); } } public static void main(String args[]) { Queen8 queen = new Queen8(); }}
- 八皇后 n皇后 问题
- 八皇后N皇后问题
- 八皇后问题
- 八皇后问题
- 八皇后问题
- 八皇后问题(2)
- 八皇后问题(3)
- 八皇后问题
- 八皇后问题程序
- 浅谈八皇后问题
- 八皇后问题
- 八皇后问题
- 八皇后问题
- 八皇后问题
- 八皇后问题求解
- 八皇后问题
- 八皇后问题
- 八皇后问题
- 当Java代码遇上抽象、重载加重写,一切都不美好了
- 64位Ubuntu12.04下安装arm-linux-gdb,以及解决no termcap library found的方法
- 关于assetbundle的详解等
- 链接
- 线索二叉树
- 八皇后问题
- Gradle构建控制Log开关——BuildConfig\自定义
- Android Battery一些信息获取方法
- is not allowed to connect to this MySQL server解决办法
- verilog-for 语句实例
- git 命令(1)
- 欢迎使用CSDN-markdown编辑器
- 滑动返回上一个界面的实现
- 改善 ASP.NET MVC 代码库的 5 点建议