问题描述: N皇后问题。在N*N格的棋盘上放置N个皇后,使这些皇后不能互相攻击,即皇后不能在同一行,同一列或者同一对角线上。
解决方法:解决这个问题的最典型的算法就是回溯法。回溯法解题通常包含以下三个步骤:
(1)针对所给问题,定义问题的解空间;
(2)确定易于搜索的解空间结构;
(3)以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索;
那么怎么运用回溯法来解决这个问题呢?
1) 首先找出解空间:给棋盘的行和列都编上1到N的号码,皇后也给编上1到N的号码。由于一个皇后应在不同的行上,为不失一般性,可以假定第i个皇后将放在第i行上的某列。因此N皇后问题的解空间可以用一个N元组(X1,X2,…..Xn)来表示,其中Xi是放置皇后i所在的列号。这意味着所有的解都是N元组(1,2,3,…….,N)的置换。解空间大小为N!。
2) 然后我们再找找有什么约束条件。在这里因为解空间已经给我们排除了不在同一行(因为每个皇后分别已经对应不同的行号)的约束条件。我们要判断的是不在同一列和不在同一斜线的约束。因为Xi表示皇后所在的列号,所以如果存在X(t)=X(i)那么肯定存在第k个皇后和第i个皇后同列。所以不同列的判段条件是X(t)!=X(i)。判断是否同一斜线的话,根据基本的数学知识我们可以很容易知道|X(i)-X(t)|=|i-t|就是表示在同一斜线,只要不符合这一条件就行。
下面就是我写的java代码,里面也有很详细的步骤解析
哎呀妈呀这marodown编辑器怎么没有表情可用?。。。
:)
import java.util.Scanner;
//n皇后问题
public class NQueen {
int N;//n个皇后
int sum=0;//解决方案数目
int[] x;//x[i]表示第i行存放皇后的列数为x[i]
public int countQueen(int n){
N=n;
x=new int[N+1];
backtrack(1);
return sum;
}
public static void main(String[] args) {
NQueen nq=new NQueen();
Scanner input=new Scanner(System.in);
System.out.println("请输入您的皇后数量:");
int n=input.nextInt();
System.out.println("解决方案有"+nq.countQueen(n)+"种");
input.close();
}
public void backtrack(int t){
if(t>N){//遍历到了最后一层,说明这种方法可以
sum++;
/*
* 执行完sum++然后自动返回上一层,检验是否还含有其他可行方案。一步一步地返回
* 直到第一层,也是一个for()循环遍历每一种可能
*/
}
else{
for(int i=1;i<=N;i++){//第t行有n个可能,也就是说第t个皇后可以存放的有n种可能
x[t]=i;//一种一种试,不行就下一列
if(place(t)){
backtrack(t+1);
}
}
}
}
public boolean place(int col){//此时已经存放好了col-1个皇后,检查现在放的是否跟前面放的皇后有冲突
for(int i=1;i<col;i++){
if(Math.abs(col-i)==Math.abs(x[col]-x[i])||x[col]==x[i]){
return false;
}
}
return true;
}
}