八皇后
1、介紹
八皇后問題是一個以國際象棋爲背景的問題:如何能夠在 8×8 的國際象棋棋盤上放置八個皇后,使得任何一個皇后都無法直接喫掉其他的皇后?爲了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。八皇后問題可以推廣爲更一般的n皇后擺放問題:這時棋盤的大小變爲n1×n1,而皇后個數也變成n2。而且僅當 n2 ≥ 1 或 n1 ≥ 4 時問題有解。
2、思路
在一個8x8的棋盤下放置皇后,當前皇后的相同行、列,對角線,及反對角線都不能有其它皇后,否則就會被喫掉。所以爲了保證八個皇后都能被放置不被喫。將用回溯算法來求取八皇后被放置的所有解。回溯就是當前的皇后無法放置時,回退到前一個皇后的狀態,改變前一個皇后的位置,在改變了前一個皇后位置後,接下來重新放置當前皇后,找到合適位置,放置皇后,進行下一步,找不到合適位置,則繼續回退,前一個的位置都試過還不行,則繼續回退前一個的前一個,以此類推直到找到最後一個皇后能放置的位置,那麼這就是一個解。
3、核心代碼
int try(int i) {
int j, k, q = 0;
//遍歷各行,尋找可放置皇后之處
for (j = 0; j < n; j++) {
if (row[j] == 1 // j 行可放子
&& d1[i - j + n - 1] == 1 // 主對角線可放子
&& d2[i + j] == 1) // 反對角線可放子
{
x[i] = j; // 記錄:在 i列 j行放置皇后
set(i, j, 0); // 放置皇后:設置 j行及其對角線不可放子
if (i < n - 1) { // 題未解完
try(i + 1); // 嘗試下一步
} else // 得到最終解
{
output();
}
set(i, j, 1); // 移去皇后(回溯):恢復 j行及其對角線可放子
}
}
}
4、完整代碼
#include <stdio.h>
#include <stdlib.h>
#define n 8 //皇后個數
int x[n]; // 解
int row[n], // 行
d1[2 * n - 1], // 主對角線。同一線上,座標差相同
d2[2 * n - 1]; // 反對角線。同一線上,座標和相同
int success=1; //解的個數
// 在 j行 i列,放置皇后(e = 0) 或移去皇后(e = 1)
int set(int i, int j, int e) {
row[j] = e;
d1[i - j + n - 1] = e;
d2[i + j] = e;
}
//輸出解
void output(){
int i;
printf("第%d組解: ", success++);
for (i = 0; i < n; i++)
printf("%3d", x[i]);
printf("\n");
}
//在第 i列,選擇放置皇后的行
int try(int i) {
int j, k, q = 0;
//遍歷各行,尋找可放置皇后之處
for (j = 0; j < n; j++) {
if (row[j] == 1 // j 行可放子
&& d1[i - j + n - 1] == 1 // 主對角線可放子
&& d2[i + j] == 1) // 反對角線可放子
{
x[i] = j; // 記錄:在 i列 j行放置皇后
set(i, j, 0); // 放置皇后:設置 j行及其對角線不可放子
if (i < n - 1) { // 題未解完
try(i + 1); // 嘗試下一步
} else // 得到最終解
{
output();
}
set(i, j, 1); // 移去皇后(回溯):恢復 j行及其對角線可放子
}
}
}
int main() {
int i;
// 設置各行可放子
for (i = 0; i < n; i++)
row[i] = 1;
// 設置各對角線可放子
for (i = 0; i < 2 * n - 1; i++) {
d1[i] = d2[i] = 1;
}
//執行
try(0);
}
5、相關文件:Github