继续思考“n-queens”问题
这次我们不是输出皇后的排列情况,而是输出n皇后问题一共有多少种解法
注:n 皇后问题是在 n*n 棋盘上放置 n 个皇后, 并且使它们互相不在对方的攻击范围之内的摆放方法;
注注:皇后的攻击范围是上、下、左、右、左上、左下、右下、右上共 8 个方向, 且不限距离。
public int totalNQueens (int n) {
// write code here
int res = 0;
int[] col = new int[n]; //一行只有一个,只需要记录该列皇后位置
int[] leftLine = new int[2 * n - 1]; //从左往右方向的对角线,当同一个对角线和相同
int[] rightLine = new int[2 * n - 1]; //从右往左方向的对角线,同一个线r1-r2==l1-l2,或者保证索引为正数是(n-1)-(r1-l1)==(n-1)-(r2-l2)
res = queen(0, n, res, col, leftLine, rightLine);
return res;
}
public int queen(int restCol, int n, int res, int[] col, int[] leftLine, int[] rightLine) {
if (restCol == n) {
res++;
return res;
}
for (int restRaw = 0; restRaw < n; restRaw++) {
if (col[restRaw] == 0 && leftLine[restRaw + restCol] == 0 && rightLine[n - 1 - restRaw + restCol] == 0) {
col[restRaw] = 1;
leftLine[restRaw + restCol] = 1;
rightLine[n - 1 - restRaw + restCol] = 1;
res = queen(restCol + 1, n, res, col, leftLine, rightLine);
col[restRaw] = 0;
leftLine[restRaw + restCol] = 0;
rightLine[n - 1 - restRaw + restCol] = 0;
}
}
return res;
} //暴力回溯,请勿模仿
public class Solution { int count = 0;
public int totalNQueens(int n) {
int[] a = new int[n];
helper(a,0,n);
return count;
}
public void helper(int[] a,int k,int n){
if(k >= n){
count ++;
return;
}
for(int i = 0;i<n ;i++){
a[k] = i;
if(check(a,k)){
helper(a,k+1,n);
}
}
}
public boolean check(int[] a,int k){
boolean flag = true;
for(int i = 0;i<k;i++){
if(Math.abs(a[i] - a[k]) == k - i || a[i] == a[k]) return false;
}
return flag;
}
} //应该还是要搜索吧?
public class Solution {
int count = 0;
public int totalNQueens(int n) {
int[] cols = new int[n];
int[] slash1 = new int[2*n-1];
int[] slash2 = new int[2*n-1];
DFS(n, 0, cols, slash1, slash2);
return count;
}
public void DFS( int n, int cur, int cols[], int slash1[], int slash2[]) {
if(cur == n) {
count++;
}
for(int i=0; i<n; i++) {
if(cols[i] != 1 && slash1[cur + i] != 1 && slash2[n-1-cur+i] != 1) {
cols[i] = 1;
slash1[cur + i] = 1;
slash2[n-1-cur+i] = 1;
DFS(n, cur+1, cols, slash1, slash2);
cols[i] = 0;
slash1[cur + i] = 0;
slash2[n-1-cur+i] = 0;
}
}
}
}
/**
* don't need to actually place the queen,
* instead, for each row, try to place without violation on
* col/ diagonal1/ diagnol2.
* trick: to detect whether 2 positions sit on the same diagnol:
* if delta(col, row) equals, same diagnol1;
* if sum(col, row) equals, same diagnal2.
*/
private final Set<Integer> occupiedCols = new HashSet<Integer>();
private final Set<Integer> occupiedDiag1s = new HashSet<Integer>();
private final Set<Integer> occupiedDiag2s = new HashSet<Integer>();
public int totalNQueens(int n) {
return totalNQueensHelper(0, 0, n);
}
}
private int totalNQueensHelper(int row, int count, int n) {
for (int col = 0; col < n; col++) {
if (occupiedCols.contains(col))
continue;
int diag1 = row - col;
if (occupiedDiag1s.contains(diag1))
continue;
int diag2 = row + col;
if (occupiedDiag2s.contains(diag2))
continue;
// we can now place a queen here
if (row == n-1)
count++;
else {
occupiedCols.add(col);
occupiedDiag1s.add(diag1);
occupiedDiag2s.add(diag2);
occupiedCols.add(col);
occupiedDiag1s.add(diag1);
occupiedDiag2s.add(diag2);
count = totalNQueensHelper(row+1, count, n);
// recover
occupiedCols.remove(col);
occupiedDiag1s.remove(diag1);
occupiedDiag2s.remove(diag2);
}
}
return count;
}
}