之前听过一个学长讲了n皇后问题,于是深有体会,想借机和大家分享一下用回溯法解决此问题的过程。
一.问题的描述:
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同 一列或同一斜线上的棋子。n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上。
输入:
给定棋盘的大小n (n ≤ 13)
输出:
输出有多少种放置方法。
二.问题的解决:
通过回溯法来解决,需要一个约束函数和一个限界函数选出满足条件,这两个函数统称为剪枝函数。
约束函数是排除那些同行,同列,同一斜线的情况。
写道
/**
* 约束函数
* 判断条件 只要任何两个皇后不在同一斜线,同行或者同列
* @return
*/
public boolean Place(int k){
for(int i=1;i<k;i++)
if(Math.abs(k-i)==Math.abs(a[k]-a[i])||(a[k]==a[i]))
return false;
return true;
}
* 约束函数
* 判断条件 只要任何两个皇后不在同一斜线,同行或者同列
* @return
*/
public boolean Place(int k){
for(int i=1;i<k;i++)
if(Math.abs(k-i)==Math.abs(a[k]-a[i])||(a[k]==a[i]))
return false;
return true;
}
我这里其实限界条件和回溯函数写在了一起。当t>n,我们就已经找到了一种方案。
//回溯函数
public void Backtrack(int t){
if(t>n)
sum++;
else
for(int i=1;i<=n;i++){
a[t]=i;
if(Place(t))
Backtrack(t+1);
}
}
我定义了一个n皇后类,里面包含约束函数,回溯函数,打印函数,以下是程序的完整代码
package queenSort;
/**
* 这是n皇后算法类
* @author Administrator
*
*/
public class QueenCode {
private int a[];
private int n=0;
private long sum=0;
/**
*
* @param n
* @param a a[i]表示的意思为皇后放在第i行第a[i]列
*/
public QueenCode(int n,int a[]){
this.n=n;
this.a=a;
}
/**
* 约束函数
* 判断条件 只要任何两个皇后不在同一斜线,同行或者同列
* @return
*/
public boolean Place(int k){
for(int i=1;i<k;i++)
if(Math.abs(k-i)==Math.abs(a[k]-a[i])||(a[k]==a[i]))
return false;
return true;
}
/**
*
* @param t 表示第i行
*/
//回溯函数
public void Backtrack(int t){
if(t>n)
sum++;
else
for(int i=1;i<=n;i++){
a[t]=i;
if(Place(t))
Backtrack(t+1);
}
}
public void PrintSort(){
System.out.println("当前的皇后摆法有"+sum+"种");
}
}
*********************************************************
package queenSort;
public class QueenMain {
public static void main(String args[]){
int n=8;
int a[]=new int[n+1];
for(int i=0;i<n;i++){
a[i]=0;
}
QueenCode code=new QueenCode(n,a);
code.Backtrack(1);
code.PrintSort();
}
}
以上的方法确实很简单就算出方案个数,但是就具体的摆法代码本身并没有给出。如果希望实现,需要
加入二维数组来记录摆放的棋子。
细心的读者和许多朋友都知道,就是如果n>=14的话,我们的eclipse是会报栈溢出的,这就关系到java的
栈大小是固定的。一旦超过里面层数,就不再给函数分配空间了。