在N*N的棋盘上摆N个皇后,要求任意两个皇后不同行,不同列,不在一条斜线上,给定一个整数n,返回n皇后的摆法有多少种。
例如:n=1 返回1
n=2 返回0
n=3 返回0
n=8 返回92
N皇后问题
public class NQueens {
public static int num1(int n){
if (n < 1){
return 0;
}
int[] record = new int[n];
return process1(0, record, n);
}
public static int process1(int i, int[] record, int n){
if (i==n){
return 1;
}
int res = 0;
for (int j=0; j<n; j++){
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 void main(String[] args) {
// int res1 = num1(1);
// int res2 = num1(2);
// int res3 = num1(3);
// int res4 = num1(4);
int res8 = num1(8);
// System.out.println(res1);
// System.out.println(res2);
// System.out.println(res3);
// System.out.println(res4);
System.out.println(res8);
// System.out.println(1<<2);
}
}
N皇后问题优化
优化的部分是常数比分,对比之前的皇后位置,判断当前有哪些位置可以放置皇后。之前选择数组一个个遍历对比。此处优化借助位运算,32个bit位,当皇后越多时,此方法时间越短
private static int num2(int n){
//请不要超过32皇后问题,否则请用long等类型
if (n < 1 || n > 32){
return 0;
}
int upperLimit = n == 32 ? -1 : ((1<<n)-1);
return process2(upperLimit,0,0,0);
}
//colLim 列的限制,1的位置不能放皇后,0的位置能放皇后
//leftDiaLim 左斜线的限制,1的位置不能放皇后,0的位置能放皇后
//rightDiaLim 右斜线的限制,1的位置不能放皇后,0的位置能放皇后
private static int process2(int upperLimit, int colLim, int leftDiaLim, int rightDiaLim) {
if (upperLimit == colLim){
return 1;
}
int mostRightOne = 0;
//pos 1可以放皇后,0不能,所有候选皇后的位置都在pos上
int pos = upperLimit & (~(colLim | leftDiaLim | rightDiaLim));
int res = 0;
while (pos != 0){
// mostRightOne = pos & (~(pos-1));
//最右侧的1提取出来
mostRightOne = pos & (~pos+1);
pos = pos - mostRightOne;
//在最右侧1的位置放皇后,接下来下一行的限制,
//列限制或上最右侧1的位置,左斜线限制或上最右侧1的位置,再左移一位
//右斜线限制或上最右侧1的位置,再右移一位
//>>:带符号右移。正数右移高位补0,负数右移高位补1
//>>>:无符号右移。无论正数还是负数,高位通通补0
res += process2(upperLimit, colLim | mostRightOne,
(leftDiaLim | mostRightOne) << 1,
(rightDiaLim | mostRightOne) >>> 1);
}
return res;
}