n后问题-回溯法

简介:

问题描述:

  在n*n的棋盘上放置彼此不受攻击的n个皇后。按国际象棋的规则,皇后可以与之处在同一行或者同一列或同一斜线上的棋子。

  n后问题等价于在n*n格的棋盘上放置n皇后,任何2个皇后不放在同一行或同一列的斜线上。

算法设计:

  |i-k|=|j-l|成立,就说明2个皇后在同一条斜线上。可以设计一个place函数,测试是否满足这个条件。

  1 当i>n时,算法搜索至叶节点,得到一个新的n皇后互不攻击放置方案,当前已找到的可行方案sum加1.

  2 当i<=n时,当前扩展结点Z是解空间中的内部结点。该结点有x[i]=1,2,3....n共n个儿子节点。

    对当前扩展结点Z的每个儿子节点,由place检察其可行性。并以深度优先的方式递归地对可行子树,或剪去不可行子树。

算法描述: 

复制代码
#include <iostream>
#include <cstdlib>
using namespace std;
class Queen{
    friend int nQueen(int);
private:
    bool Place(int k);
    void Backtrack(int t);
    int n,
        * x;
    long sum;
};
bool Queen::Place(int k)
{
    for(int j=1;j<k;j++)
        if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
            return false;
    return true;
}
void Queen::Backtrack(int t)
{
    if(t>n)
        sum++;
    else
        for(int i=1;i<=n;i++)
        {
            x[t] = i;
            if(Place(t))
                Backtrack(t+1);
        }
}
int nQueen(int n)
{
    Queen X;
    X.n = n;
    X.sum = 0;
    int *p = new int [n+1];
    for(int i=0;i<=n;i++)
        p[i] = 0;
    X.x = p;
    X.Backtrack(1);
    delete [] p;
    cout<<X.sum<<endl;
    return X.sum;
}
int main()
{
    nQueen(4);
    nQueen(2);
    nQueen(3);
    return 0;
}
复制代码

执行结果:

迭代回溯:

数组x记录了解空间树中从根到当前扩展结点的路径,这些信息已包含了回溯法在回溯时所需要的信息。利用数组x所含的信息,可将上述回溯法表示成非递归形式,进一步省去O(n)递归栈空间。

  n后问题的非递归迭代回溯法Backtrack可描述如下:

复制代码
#include <iostream>
#include <cstdlib>
using namespace std;
class Queen{
    friend int nQueen(int);
private:
    bool Place(int k);
    void Backtrack(void);//.........
    int n,
        * x;
    long sum;
};
bool Queen::Place(int k)
{
    for(int j=1;j<k;j++)
        if( ( abs(k-j) == abs(x[j]-x[k]) ) ||( x[j] == x[k] ) )
            return false;
    return true;
}
void Queen::Backtrack(void)//......
{
    x[1] = 0;
    int k = 1;
    while(k>0)
    {
        x[k]+=1;
        while( (x[k]<=n) && !(Place(k)) )//k还不是最后的叶子结点,且位置没有冲突
            x[k] += 1;
        if(x[k] <= n)
            if(k == n)//k是叶子结点
                sum++;
            else
            {
                k++;
                x[k] = 0;
            }
        else
            k--;
    }
}
int nQueen(int n)
{
    Queen X;
    X.n = n;
    X.sum = 0;
    int *p = new int [n+1];
    for(int i=0;i<=n;i++)
        p[i] = 0;
    X.x = p;
    X.Backtrack();//......
    delete [] p;
    cout<<X.sum<<endl;
    return X.sum;
}
int main()
{
    nQueen(4);
    nQueen(2);
    nQueen(3);
    return 0;
}
复制代码

执行结果:

本文转自博客园xingoo的博客,原文链接:n后问题-回溯法,如需转载请自行联系原博主。
相关文章
|
11月前
|
算法 索引
回溯算法
回溯算法
56 0
|
4月前
|
机器学习/深度学习 人工智能 算法
回溯算法是怎样的
回溯算法,择优搜索:树的深搜+剪枝
|
5月前
|
算法 C++
回溯算法详解
回溯算法详解
65 0
|
算法
这一次,真正理解回溯算法
回溯算法思想很简单,大部分都是用来解决广义搜索问题:从一组可能解中,选出一个满足要求的解。 回溯非常适合用递归实现,剪枝是提高回溯效率的一种技巧,无需穷举搜索所有情况。 回溯算法可解决很多问题,如DFS、八皇后、0-1背包、图的着色、旅行商、数独、全排列、正则表达式匹配等。
168 0
这一次,真正理解回溯算法
|
机器学习/深度学习 算法 网络协议
|
存储 算法
【回溯算法篇】组合问题(上)
【回溯算法篇】组合问题(上)
【回溯算法篇】组合问题(上)
【回溯算法篇】组合问题(下)
【回溯算法篇】组合问题(下)
【回溯算法篇】组合问题(下)
回溯法
回溯法也可以叫做回溯搜索法,它是一种搜索的方式。 回溯是递归的副产品,只要有递归就会有回溯。 所以以下讲解中,回溯函数也就是递归函数,指的都是一个函数。 回溯法的效率 回溯法的性能如何呢,这里要和大家说清楚了,虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法。 因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。 那么既然回溯法并不高效为什么还要用它呢? 因为没得选,一些问题能暴力搜出来就不错了,撑死了再剪枝一下,还没有更高效的解法。 此时大家应该好奇了,都什么问题,这么牛逼,只能暴力搜索。 回溯法
|
算法
【算法】 八皇后问题之回溯法
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。每次填满第一行第一列,当不满足时候,试下第一行第二列,依次进行,递归的出口为找到第八个点,跳出递归。,在循环里面还要判断是否满足不同行,不同列,不同对角线。使用回溯法来解决该问题,下面的代码是我看到过的最精简的代码,相关的注释都写在代码上了。运行得出结果,总共有92中结果。
239 0