【回溯法】八皇後問題(遞歸和非遞歸)
先貼代碼,分遞歸回溯法和非遞歸回溯法
遞歸回溯法,代碼如下:
// test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <stdio.h> using namespace std; int a[9] = {0}; int n = 8; int count = 0; bool check(int arr[], int n) { for (int i = 2; i <= n; ++i)for(int j = 1; j <= i-1; ++j) if (arr[i] == arr[j] || (abs(arr[i]-arr[j]) == abs(i-j))) return false; return true; } void printQueens(int a[]) { printf("第%d種情況:", count); for (int i = 1; i <= n; ++i) printf("%d",a[i]); printf("\n"); count++; } void searchQueens8(int r) { if (r > n) printQueens(a); for (int i = 1; i <= n; ++i) { a[r] = i; if (check(a, r)) { searchQueens8(r+1); } } } int _tmain(int argc, _TCHAR* argv[]) { searchQueens8(1); return 0; }
非遞歸回溯法,代碼如下:
#pragma once #include "stdafx.h" const int N = 8; int cszStack[9]; int sum = 0; int top; void printQueenStack() { printf("No.%d:", sum); for (int i = 1; i <= N; ++i) printf("%d", cszStack[i]); printf("\n"); sum++; } // k表示第k行 bool judge(int k) { if (k == 1) return true; int i; for (i = 1; i < k; ++i) { if (cszStack[i] == cszStack[k]) return false; if (abs(k-i) == abs(cszStack[k] - cszStack[i])) return false; } return true; } void putQueen() { top = 1; while(top > 0) { cszStack[top]++; // 擺放一個皇後 // 如果第top行的皇後沒有擺放出第8列,那就一直找到它在top行的合法位置 while((cszStack[top] <= N) && (!judge(top))) cszStack[top]++; if (cszStack[top] <= N) { if (top == N) { printQueenStack(); // 輸出結果 } else { top++; cszStack[top] = 0; } } else { // 在第top行8列全部不能放置皇後,說明前面幾行的擺放不合理,所以要退回上一行 top--; } } } void initStack() { for (int i = 0; i <= N; ++i ) cszStack[i] = 0; sum = 0; top = 0; } void searchQueueStack() { initStack(); putQueen(); } int _tmain(int argc, _TCHAR* argv[]) { //SearchQueens8(1); searchQueueStack(); return 0; }
指導思想:
走不通,就掉頭;
檢查合格才繼續往下走;遇到不合格就是掉頭;
能進則進,不能進則換,不能換則退;
解空間:一顆樹空間
擴展規則:深度優先策略
設計過程:(1)確定問題的解空間;(2)確定結點的擴展規則;(3)搜索解空間
退回到上一狀態的過程叫做回溯,枚舉下一個狀態的過程叫做遞歸;
回溯就像人走迷宮,先選擇一個前進方向嘗試,一步步試探,在遇到死胡同不能再往前的時候就會退到上一個分支點,另選一個方向嘗試,而在前進和回撤的路上都設置一些標記,以便能夠正確返回,直到達到目標或者所有的可行方案都已經嘗試完為止。
回溯法應用——算法說明
(1) 八皇後問題中的核心代碼
遍歷過程函數;check函數;
(2) 解決此類問題的核心內容
解空間樹的搜索算法;估值/判斷函數:判斷哪些狀態適合繼續擴展,或者為答案狀態;
遞歸算法框架:
int a[n];
Queens(int k)
{
if (k > n)
// 即表示最後一個皇後擺放完畢,輸出結果;
else
//枚舉k個皇後所有可能路徑
for (int i = 下界;I <= 上界; i++)
{// 依次從列頂端開始搜索,一直到列底端,直到找到合適的位置,如果未找到,自動返回上層遞歸
a[k] = i;
if (check(a,k))
// 遞歸擺放下一個皇後Queens(k+1);
}
}
非遞歸算法框架:
int a[n],i;
初始化數據a[];
i = 1;
while (i > 0(有路可走)) and (未達到目標)// 還未回溯到頭
{
if (i == n)
搜索到一個解,輸出;// 搜索到葉結點
else
{
a[i]第一個可能的值
while(a[i]不滿足約束條件且在搜索空間內)
a[i]下一個可能的值;
if(a[i]在搜索空間內)
{ 標識暫用的資源;i=i+1;} // 擴展下一個結點
else
{清理所占的狀態空間;i=i-1;} // 回溯
}
}
參考鏈接:https://wenku.baidu.com/view/d1e9d6fe02020740bf1e9bce.html?from=search
【回溯法】八皇後問題(遞歸和非遞歸)