C語言-求八皇后所有解

八皇后

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章