【回溯法】八皇后问题(递归和非递归)

先贴代码,分递归回溯法和非递归回溯法

递归回溯法,代码如下:

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

猜你喜欢

转载自www.cnblogs.com/gwzz/p/9197445.html