在 8×8 棋盤放 8 個皇后,任意兩個不同行、不同列、不同對角線。
用一維數組 pos[8] 表示:pos[row] = col 第 row 行皇后放在 col 列。
bool is_safe(int row, int col, int *pos) {
for (int r = 0; r < row; r++) {
int c = pos[r];
if (c == col) return false; // 同列
if (r - c == row - col) return false; // 主對角線 (row-col 恒定)
if (r + c == row + col) return false; // 副對角線 (row+col 恒定)
}
return true;
}
void solve(int row, int *pos, int *count) {
if (row == 8) { // 找到一組解
(*count)++;
print_board(pos, *count);
return;
}
for (int col = 0; col < 8; col++) {
if (is_safe(row, col, pos)) {
pos[row] = col; // 放置
solve(row + 1, pos, count); // 遞歸下一行
// pos[row] = -1; // 回溯(可選,下輪會覆蓋)
}
}
}
#include
#include
#define N 8
void print_board(int *pos, int sol_num) {
printf("\n解 %2d:\n", sol_num);
for (int r = 0; r < N; r++) {
for (int c = 0; c < N; c++)
printf("%c ", (pos[r] == c) ? '♛' : '·');
puts("");
}
}
bool is_safe(int row, int col, int *pos) {
for (int r = 0; r < row; r++) {
int c = pos[r];
if (c == col || r - c == row - col || r + c == row + col)
return false;
}
return true;
}
void solve(int row, int *pos, int *count) {
if (row == N) {
print_board(pos, ++(*count));
return;
}
for (int col = 0; col < N; col++) {
if (is_safe(row, col, pos)) {
pos[row] = col;
solve(row + 1, pos, count);
}
}
}
int main() {
int pos[N] = {0};
int count = 0;
solve(0, pos, &count);
printf("\n總共 %d 個解\n", count); // 92
return 0;
}
| 點 | 說明 |
|---|---|
| 一維數組表示 | pos[row]=col 隱含「每行一皇后」,省去行沖突檢查 |
| 對角線判斷 | 主對角線 row-col 恒定,副對角線 row+col 恒定 |
| 回溯本質 | 深度優先搜索 (DFS) + 剪枝,狀態空間樹 |
| 解的數量 | 8 皇后共有 92 個解(含對稱),本質不同 12 個 |
| 擴展到 N 皇后 | 將 8 改為常量/參數 N,pos 動態分配 |
// 利用位掩碼表示列、主對角線、副對角線佔用
void solve_bit(int row, int cols, int diag1, int diag2, int *count) {
if (row == N) { (*count)++; return; }
// 可用位 = 所有列 & ~(佔用列 | 佔用主對角線 | 佔用副對角線)
int available = ((1 << N) - 1) & ~(cols | diag1 | diag2);
while (available) {
int bit = available & -available; // 取最低位 1
available -= bit;
solve_bit(row + 1, cols | bit, (diag1 | bit) << 1, (diag2 | bit) >> 1, count);
}
}
// 主調用:solve_bit(0, 0, 0, 0, &count);
位運算版無分支預測失敗、無數組訪問、極適合 CPU 流水線,**比數組版快 10-50 倍**。
pos[row]=col + 對角線數學判斷 = 最清晰實現。DFS(狀態) { if(終止) 記錄; for(選擇) if(合法) { 標記; DFS(新狀態); 回溯; } }。