N皇后问题是指在N*N的棋盘上要摆N个皇后,要求任何两个皇后不同行、不同列,也不在同一条斜线上。
给定一个整数n,返回n皇后的摆法有多少种。
举例: n=1,返回1。
n=2或3,2皇后和3皇后问题无论怎么摆都不行,返回0。
n=8,返回92。
public class Code09_NQueens {public static int num1(int n) {if (n < 1) {return 0;}int[] record = new int[n]; // record[i] --> i 行的皇后放在了第几列return process1(0, record, n);}// i:表示来到了第几行// record:之前摆放的皇后,都在这个数组中,即之前 i-1 行的皇后的摆放位置// n:表示整体一共多少行// 返回值是:摆完所有的皇后,合理的摆法有多少种public static int process1(int i, int[] record, int n) {if (i == n) {return 1;}int res = 0;// 在 i 行,尝试所有的列:jfor (int j = 0; j < n; j++) {// 当前i行的皇后,放在第j列,会不会和之前(0...i-1)的皇后共行/共列/共斜线if (isValid(record, i, j)) {// 如果是,则认为该位置是无效的// 如果不是,则认为该位置是有效的record[i] = j;res += process1(i + 1, record, n);}}return res;}public static boolean isValid(int[] record, int i, int j) {for (int k = 0; k < i; k++) {if (j == record[k] || Math.abs(record[k] - j) == Math.abs(i - k)) {return false;}}return true;}public static int num2(int n) {if (n < 1 || n > 32) {return 0;}int upperLim = n == 32 ? -1 : (1 << n) - 1;return process2(upperLim, 0, 0, 0);}// colLim : 列的限制,1的位置不能放皇后,0的位置可以(采用二进制来计算)// leftDiaLim :左斜线的限制,1的位置不能放皇后,0的位置可以(采用二进制来计算)// rightDiaLim :右斜线的限制,1的位置不能放皇后,0的位置可以(采用二进制来计算)public static int process2(int upperLim, int colLim, int leftDiaLim,int rightDiaLim) {if (colLim == upperLim) {return 1;}int pos = 0;int mostRightOne = 0;// 所有候选的皇后位置都在 pos 上,1为可选位置,0为不可选位置pos = upperLim & (~(colLim | leftDiaLim | rightDiaLim));int res = 0;while (pos != 0) {mostRightOne = pos & (~pos + 1);pos = pos - mostRightOne;res += process2(upperLim, colLim | mostRightOne,(leftDiaLim | mostRightOne) << 1,(rightDiaLim | mostRightOne) >>> 1);}return res;}public static void main(String[] args) {int n = 14;long start = System.currentTimeMillis();System.out.println(num2(n));long end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");start = System.currentTimeMillis();System.out.println(num1(n));end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");}}
二 采用回溯法
/*** 算法:回溯法* 问题:八皇后* @author win*/public class EightQueen {public static int num = 0;//累计方案public static final int MAXQUEEN = 8;public static int[] cols = new int[MAXQUEEN];//定义cols数组,表示八列棋子摆放的位置/***** @param n 填第n列的皇后*/public void getCount(int n){boolean [] rows = new boolean[MAXQUEEN];//记录每列每个方格是否可以放皇后。为true表示不能放for(int m =0;m<n;m++){rows[cols[m]] = true;int d = n - m;//斜对角//正斜方向if(cols[m] - d>=0){rows[cols[m] - d] = true;}//反斜方向if((cols[m]+d)<=MAXQUEEN-1){rows[cols[m] + d] = true;}}//到此知道了哪些位置不能放皇后for(int i = 0;i<MAXQUEEN;i++){if(rows[i]){//不能放continue;}cols[n] = i;if(n<MAXQUEEN-1){getCount(n+1);}else{//如果n = MAXQUEEN-1;表示找到了一套完整的方案num++;printQueen();}//下面可能仍有合法位置}}private void printQueen() {System.out.println("第"+num+"种方案");for(int i = 0;i<MAXQUEEN;i++){for(int j=0;j<MAXQUEEN;j++){if(i == cols[j]){System.out.print("0 ");}else{System.out.print("+ ");}}System.out.println();}}public static void main(String[] args) {EightQueen eightQueen = new EightQueen();eightQueen.getCount(0);}}
