问题:在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
抽象:n后问题等价于在n×n的棋盘上放置n个棋子,任何2个棋子不在同一行或同一列或同一斜线上。
思路:要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行、同一列、同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇后放置在第i行的哪一列,所以在放置第i个皇后的时候,可以从第1列判断起,如果可以放置在第1个位置,则跳到下一行放置下一个皇后。如果不能,则跳到下一列...直到最后一列,如果最后一列也不能放置,则说明此时放置方法出错,则回到上一个皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。当第n个皇后放置成功后,即得到一个可行解,此时再回到上一个皇后重新放置寻找下一个可行解...如此后,即可找出一个n皇后问题的所有可行解。
代码如下:
package test;
/**
* 回溯法求N皇后问题
*
* @author yanghang
*
*/
public class Huisu {
static int n = 14; // 皇后个数,n必须大于0
static int sum = 0; // 可行解个数
static int[] x = new int[n + 1]; // 皇后放置的列数,从1开始
/**
* 计算当前摆放位置是否可行
*
* @param k
* @return
*/
public static boolean place(int k) {
int i;
for (i = 1; i < k; i++)
if (Math.abs(k - i) == Math.abs(x[k] - x[i]) || x[k] == x[i])
return false;
return true;
}
/**
* 递归求解,时间复杂度为为n!
*
* @param t
* @return
*/
public static int backtrace(int t) {
// 当放置的皇后超过n时,可行解个数加1
if (t > n)
sum++;
else
for (int i = 1; i <= n; i++) {
// 标明第t个皇后放在第i列
x[t] = i;
// 如果可以放在某一位置,则继续放下一皇后
if (place(t))
backtrace(t + 1);
}
return sum;
}
/**
* 递推求解,时间复杂度为为n!
* @return
*/
public static int backtrace() {
//将当前列初始化为0
x[1] = 0;
//从第一行开始试探
int t = 1;
while (t > 0) {
//往前挪一列
x[t] += 1;
//列没出界并且当前摆放位置不可行,继续向前挪一列
while (x[t] <= n && !place(t))
x[t]++;
//当前列还未出界,可行位置
if (x[t] <= n)
//已经是最后一行
if (t == n)
sum++;
//不是最后一行,行数加一,继续试探
else
x[++t] = 0;
//当前列已出界,则返回上一行继续试探
else
t--;
}
return sum;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(backtrace(1));
}
}