问题:在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)); } }