1. 程式人生 > >【回溯法】八皇後問題(遞歸和非遞歸)

【回溯法】八皇後問題(遞歸和非遞歸)

問題 一個 bce and 核心 皇後 條件 IE 上一個

先貼代碼,分遞歸回溯法和非遞歸回溯法

遞歸回溯法,代碼如下:

// 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

【回溯法】八皇後問題(遞歸和非遞歸)