8×8 棋盤放置 8 個皇后,任兩個不同行、不同列、不同對角線。用一維陣列 col[row] = column 表示。
對任意 i < j:
col[i] != col[j]|col[i] - col[j]| != j - ipublic void solveOne() {
int[] col = new int[8];
for (int i = 0; i < 8; i++) col[i] = i; // 初始各列唯一
int attempts = 0;
while (true) {
attempts++;
shuffle(col); // Fisher-Yates 洗牌
if (isValid(col)) {
System.out.println("嘗試 " + attempts + " 次找到解: " + Arrays.toString(col));
break;
}
}
}
private void shuffle(int[] a) {
Random r = new Random();
for (int i = 0; i < a.length; i++) {
int j = r.nextInt(a.length);
int t = a[i]; a[i] = a[j]; a[j] = t;
}
}
private boolean isValid(int[] col) {
for (int i = 0; i < 8; i++)
for (int j = i + 1; j < 8; j++)
if (Math.abs(col[i] - col[j]) == j - i) return false;
return true;
}
期望嘗試次數約 8! / 92 ≈ 4400,極快得到一解。
public void solveAll() {
int start = 0_1234567; // 八進制字面值
int end = 0_7654321;
int count = 0;
for (int n = start; n <= end; n++) {
String oct = Integer.toOctalString(n);
if (oct.length() == 7) oct = "0" + oct; // 補齊前導 0
if (isValidOct(oct)) {
System.out.println(++count + ": " + oct);
}
}
System.out.println("總解數: " + count); // 92
}
private boolean isValidOct(String oct) {
for (int i = 0; i < 8; i++) {
for (int j = i + 1; j < 8; j++) {
if (oct.charAt(i) == oct.charAt(j)) return false; // 同列
if (Math.abs(oct.charAt(i) - oct.charAt(j)) == j - i) return false; // 同對角線
}
}
return true;
}
遍歷 8⁸ = 16,777,216 個八進制數,過濾重複列後驗證對角線,約 0.5 秒完成。
| 維度 | 隨機搜尋 | 八進制遍歷 | 回溯法(標準) |
|---|---|---|---|
| 目標 | 任意一解 | 所有解 | 所有解 |
| 時間複雜度 | 期望 O(8!) | O(8⁸) | O(8!) |
| 實作難度 | 低 | 中 | 中 |
| 效能 | 毫秒級 | 秒級 | 毫秒級 |
List solutions = new ArrayList<>();
int[] col = new int[8];
void backtrack(int row) {
if (row == 8) { solutions.add(col.clone()); return; }
for (int c = 0; c < 8; c++) {
col[row] = c;
if (valid(row)) backtrack(row + 1);
}
}
boolean valid(int row) {
for (int i = 0; i < row; i++)
if (col[i] == col[row] || Math.abs(col[i] - col[row]) == row - i) return false;
return true;
}
int 位元表示列、主對角線、副對角線佔用,bits = cols | diag1 | diag2,極快