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


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

遞歸回溯法,代碼如下:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM