在 N×N 棋盤上放置 N 個皇後,使任意兩個皇後不同行、不同列、不同斜線。經典 8 皇後是 N=8 特例。解的數量隨 N 增長呈指數級增長(N=8 有 92 解,去重對稱後 12 解)。
使用三個布爾數組(或位掩碼)記錄衝突:
cols[c]:列 c 是否有皇後diag1[r+c]:主對角線(行+列固定)diag2[r-c+N-1]:副對角線(行-列固定,偏移避免負索引)import java.util.*;
public class NQueens {
private int n;
private int count = 0;
private boolean[] cols, diag1, diag2;
private int[] queens; // queens[row] = col
private Set uniqueSolutions = new HashSet<>();
public int solve(int n) {
this.n = n;
cols = new boolean[n];
diag1 = new boolean[2 * n - 1];
diag2 = new boolean[2 * n - 1];
queens = new int[n];
backtrack(0);
return count;
}
private void backtrack(int row) {
if (row == n) {
// 找到一個解
count++;
printSolution();
return;
}
for (int col = 0; col < n; col++) {
if (isValid(row, col)) {
placeQueen(row, col);
backtrack(row + 1);
removeQueen(row, col);
}
}
}
private boolean isValid(int row, int col) {
return !cols[col] && !diag1[row + col] && !diag2[row - col + n - 1];
}
private void placeQueen(int row, int col) {
queens[row] = col;
cols[col] = true;
diag1[row + col] = true;
diag2[row - col + n - 1] = true;
}
private void removeQueen(int row, int col) {
cols[col] = false;
diag1[row + col] = false;
diag2[row - col + n - 1] = false;
}
private void printSolution() {
StringBuilder sb = new StringBuilder();
for (int r = 0; r < n; r++) {
sb.append('(').append(r).append(',').append(queens[r]).append(')');
}
String key = sb.toString();
if (uniqueSolutions.add(key)) { // 去重
System.out.println("解 " + count + ": " + key);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("請輸入 N (N≥4): ");
int n = sc.nextInt();
NQueens solver = new NQueens();
long start = System.currentTimeMillis();
int total = solver.solve(n);
System.out.printf("N=%d 總解數: %d, 耗時: %d ms%n", n, total, System.currentTimeMillis() - start);
}
}
請輸入 N (N≥4): 4
解 1: (0,1)(1,3)(2,0)(3,2)
解 2: (0,2)(1,0)(2,3)(3,1)
N=4 總解數: 2, 耗時: 5 ms
int 位掩碼代替布爾數組,利用 CPU 指令級並行(N≤32 時極快)