八皇后

關於八皇后所採用的回溯法,簡單點說就是高效率的“窮舉”,如果當前的這一行實在找不出可行的位置,則返回上一行重新設置位置,直到下一行能找到可行的位置爲止。

用遞歸實現如下(C++)

#include<iostream>
#include<cmath>
using namespace std;

const int MAX = 8;
int queen[MAX];  // 數組queen的下標表示行號,queen[i]表示第i行的皇后所放的位置

// 判斷當前位置的皇后是否有效
bool isValid(int currentRow) {
    for (int i = 0; i < currentRow; ++i) {
        if (queen[i] == queen[currentRow]) {    <span style="font-family: Arial, Helvetica, sans-serif;">// 與之前的皇后在同一列</span>
            return false;
        } else if (abs(queen[i] - queen[currentRow]) == currentRow - i) {    <span style="font-family: Arial, Helvetica, sans-serif;">// 與之前的皇后在同一對角線上</span>
            return false;
        }
    }
    return true;
}

// 打印出每一行的皇后所在的列數
void print() {
    for (int i = 0; i < MAX; ++i) {
        cout << queen[i] << " ";
    }
    cout << endl;
}

// 核心算法
void placeQueen(int currentRow) {
    for (int col = 1; col <= MAX; ++col) {
        if (currentRow == MAX) {        // 如果已經遞歸到第MAX行,證明前面的8行均合法,這樣一種解法便結束了
            print();
            return;
        }

        queen[currentRow] = col;
        if (isValid(currentRow)) {       // 判斷位置是否有效,是的話就進入下一行遞歸,否則繼續循環
            placeQueen(currentRow+1);
        }
    }
}

int main() {
    placeQueen(0);
}



關於核心算法是如何實現回溯的:

比如,如果currentRow==0,則開始放置第一行皇后,用一個for循環來確保每一列均能被放置。因爲是第一個,所以每一行均是有效的,這樣isValid()會返回true,進入遞歸放置第二行的皇后。同樣,第二個遞歸函數用一個for循環來確保每一列均能被放置,如果其中有一列合法,則進入第三行的放置,如果遍歷完所有的列之後仍找不出有效的位置,則遞歸結束,返回上一個遞歸函數(這裏就用到回溯的思想)。在上一個遞歸函數裏,可能循環沒有結束,因此會繼續將皇后放置到之後的列上面,然後再繼續進入下一行。這樣不斷測試下去後,知道第八行找到一個合法的位置,進入下一層遞歸placeQueen(8) 【第八行對應的currentRow是7】,這個時候全部皇后均已放好,便打印出所有的位置,緊接着return後又會回到第八行的遞歸函數,第八行的遞歸函數繼續循環,如果找出有效位置,繼續遞歸打印結果,找不到,則返回上一層遞歸函數,直到每一層遞歸函數的循環均完成後,所有的位置便全部測試完畢,遞歸結束。

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