题目:在8*8的国际象棋上摆放8个皇后,使其不能相互攻击,及任意两个皇后不得处于同一行,同一列或者赞成对角线上,请问总共有多少种符合条件的摆法。java
思路一:算法
因为八个皇后的任意两个不能处在同一行,那么这肯 定是每个皇后占据一行。因而咱们能够定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把 ColumnIndex的八个数字分别用0-7初始化,接下来咱们要作的事情就是对数组ColumnIndex作全排列。因为咱们是用不一样的数字初始化数 组中的数字,所以任意两个皇后确定不一样列。咱们只须要判断获得的每个排列对应的八个皇后是否是在同一对角斜线上,也就是数组的两个下标i和j,是否是 i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。express
package cglib;数组
public class DeleteNode{
static int g_number = 0;
public static void EightQueen( )
{
final int queens = 8;
int[] ColumnIndex=new int[queens];
for(int i = 0 ; i < queens ; ++i)
{ColumnIndex[i] = i; //初始化
System.out.println("ColumnIndex[i="+i+"]="+ColumnIndex[i]);
}
perm(ColumnIndex , 0,queens-1);
}
public static boolean Check(int ColumnIndex[] , int length)
{
int i,j;
for(i = 0 ; i <= length; ++i)
{
for(j = i + 1 ; j <= length; ++j)
{
if( i - j == ColumnIndex[i] - ColumnIndex[j] || j - i == ColumnIndex[i] - ColumnIndex[j]) //在正、副对角线上
return false;
}
}
return true;
}
public static void main(String[] args) {
EightQueen();
}
public static void Print(int buf[] , int length)
{
System.out.println("g_number="+g_number);
/*for(int i = 0 ; i <= length; ++i)
System.out.print("buf[i="+i+"]="+buf[i]);
System.out.println(); */
} app
public static void perm(int[] buf,int start,int end){
if(buf==null || end!=buf.length-1)
return ;
if(start==end){
if( Check(buf , end) ) //检测棋盘当前的状态是否合法
{
++g_number;
Print(buf , end);
}
}
else{
for(int i=start;i<=end;i++){
//System.out.println("交换前:buf[start="+start+"]="+buf[start]);
//System.out.println("交换前:buf[i="+i+"]="+buf[i]);
int temp=buf[start];
buf[start]=buf[i];
buf[i]=temp;
perm(buf,start+1,end);
temp=buf[start];函数
buf[start]=buf[i]; ui
buf[i]=temp;
//System.out.println("变回来:buf[start="+start+"]="+buf[start]);
//System.out.println("变回来:buf[i="+i+"]="+buf[i]); this
} spa
}
.net
}
}
思路2:
首先,可概括问题的条件为,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行不能放棋子。这样咱们就能写成下列程序段了:
[java] view plain copy
好了,到此为止,咱们程序的核心内容都具有了,一个基于深度优先的遍历流程和一个判断位置是否合适的算法。下面贴出运行后算出的全部可行方案(即92种,“+”号表明空棋位,“0”表明皇后所在位置)
package cglib;
public class DeleteNode{
public static int num = 0; //累计方案总数
public static final int MAXQUEEN = 8;//皇后个数,同时也是棋盘行列总数
public static int[] cols = new int[MAXQUEEN]; //定义cols数组,表示8列棋子摆放状况
public DeleteNode() {
//核心函数
getArrangement(0);
System.out.println("综上所述");
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.println("第"+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.println("/n");
}
}
public static void main(String args[]){
DeleteNode queen = new DeleteNode();
}
}
/**
* 功能:打印八皇后在8*8棋盘上的各类摆法,其中每一个皇后都不一样行、不一样列,也不在对角线上。
* 这里的“对角线”指的是全部的对角线,不仅是平分整个棋盘的那两条对角线。
*/
[java] view plain copy