八皇后(回溯法)
題目描述

在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法!
設計思路
皇后位置
用一維數組表示,數組下標是行,元素是列
int place[8] = { 0 };
衝突判斷
flag保存哪一列已經存在皇后
bool flag[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
d1記錄皇后的主對角線衝突

n - col + 7的範圍是0~14對應d1[15]
bool d1[15] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
d2記錄皇后的次對角線衝突

d2 = n + col的範圍是0~14對應d2[15]
bool d2[15] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
八皇后核心
void QueenVIII(int n) //n是行數
{
for (int i = 0; i < 8; ++i) // 每個皇后有8中可能的列
{
if ((flag[i] && d1[n - i + 7]) && d2[n + i]) // 判斷第n行第i列的位置是否危險
{
place[n] = i; // 在第n行第i列擺放皇后
flag[i] = 0; // 記錄第i列已經有皇后了
d1[n - i + 7] = 0; // 記錄這條主對角線是危險的
d2[n + i] = 0; // 記錄這條次對角線是危險的
if (n < 7 ) // 判斷八個皇后放完了沒有
{
QueenVIII(n + 1); //沒放夠就繼續遞歸放
}
else
{
output(); //放夠八個皇后就輸出
}
// 回溯(退回去看看有沒有新方法)
flag[i] = 1;
d1[n - i + 7] = 1;
d2[n + i] = 1;
}
}
}
完整程式碼
# include <stdio.h>
// 全局變數
int place[8] = { 0 }; // 保存皇后的位置,下標為行,儲存的數據為列。
bool flag[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; // 用來保存哪一列已經存在皇后
bool d1[15] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; // 從左上到右下的對角線為上對角線,每條上對角線上的行和列的差是一樣的。
bool d2[15] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; // 從左下到右下的對角線為下對角線,每條下對角線上的行和列的和是一樣的。
int key = 0; // 統計解的數量
// 函數聲明
void QueenVIII(int); // 八皇后問題
void output(void); // 輸出
// 主函數
int main(void)
{
//output();
QueenVIII(0);
return 0;
}
void QueenVIII(int n)
{
for (int i = 0; i < 8; ++i) // 每個皇后有8中可能的列
{
if ((flag[i] && d1[n - i + 7]) && d2[n + i]) // 判斷第n行第i列的位置是否危險
{
place[n] = i; // 在第n行第i列擺放皇后
flag[i] = 0; // 記錄第i列已經有皇后了
d1[n - i + 7] = 0; // 記錄這條上對角線是危險的
d2[n + i] = 0; // 記錄這條下對角線是危險的
if (n < 7 ) // 判斷八個皇后放完了沒有
{
QueenVIII(n + 1); //沒放夠就繼續遞歸放
}
else
{
output(); //放夠八個皇后就輸出
}
// 回溯(退回去看看有沒有新方法)
flag[i] = 1;
d1[n - i + 7] = 1;
d2[n + i] = 1;
}
}
}
void output(void)
{
printf("第%d種解法:\n", ++key);
for (int n = 0; n < 8; ++n)
{
for (int i = 0; i < 8; ++i)
{
if (place[n] == i)
{
printf("1 ");
}
else
{
printf("0 ");
}
}
printf("\n");
}
printf("\n");
}
