一、问题的描述
在n×n的国际象棋棋盘中放置彼此不受攻击的那个皇后,按照规则,如果n个皇后不互受攻击,则任何一个皇后不能跟其它皇后在棋盘的同一行或同一列,也不能在斜对角。
二、问题的分析
1,解的假设
自己可以动手画一个4*4的棋盘,然后将尝试将4个皇后放进棋盘,可以有两种解决方案:
显然,通过一步步尝试,解决该问题要用到回溯法,并且解的形式满足m叉树(还有另外两种是子集树和排列树),然后通过上述的限制条件剪去一些不满条件的枝(同行或同列,斜对角),问题的搜索空间深度为n(皇后的个数,严格的说应该是棋盘的列数,这里皇后的个数与期盼的列数相等)
2,确定解空间
a,根据上面的解的假设,可以定义解的形式为{x1,x2,…xi…,xn}其中xi表示在第i行xi的当前取值
b,满m叉树,深度为n
c,限制条件,n个皇后不互受攻击(不能同一列:xi != xt;不能是斜对角:|t - i| != |xt - xi|;t是用来控制深度搜索;这里无需考虑在同一行的情况)
三、代码实现
本例使用java语言实现
public class TraceBack {
final static int N = 8;
static long sum = 0;
static void print(int[] gezi) {
for(int i = 1;i <= N;i++) {
for(int j = 1;j <= N;j++) {
if(gezi[i]!=j){
System.out.print(" - ");
}else{
System.out.print(" " + gezi[i] + " ");
}
}
System.out.println();
}
System.out.println();
}
//用于判断皇后位置是否合法
static boolean place(int[] x,int t) {
for(int i = 1;i < t;i++) {
//斜对角或同列
if(Math.abs(x[t] - x[i]) == Math.abs(t - i) || x[t] == x[i]) return false;
}
return true;
}
static void btrack(int[] x, int t) {
if(t > N) {
sum++;
print(x);
}
else
for(int i = 1;i <= N;i++) {
x[t] = i;
if(place(x,t)) btrack(x,t + 1);
}
}
/**
* @param args
*/
public static void main(String[] args) {
//4×4的九宫格的回溯
int[] x = new int[N + 1];
btrack(x,1);
System.out.println(TraceBack.sum);
}
}
四,结果分析
将上述代码运行,发现当n = 8时,sum = 92;当n = 16时,结果就相当大了,运行半天还没有运行完!