• 回溯法之八皇后问题简单理解


    回溯法,简单理解就是有源可溯。基本思想要借鉴穷举法,但是它不是一味地穷举,当发现某一步不符合条件时,这一步后面的穷举操作就不进行了(俗称“剪枝”),我自己把它叫做动态穷举法。假设第一个步骤可行,那么执行第二个步骤,第三个......如果其中第三个步骤不行,那么我们再回过来(回溯),第二个步骤换一种方法尝试,然后再重新第三个步骤,第四个......直到完成任务要求为止。

    这里,以八皇后问题为例。试图把回溯法讲清楚。

    注意:递归应该是一种算法结构,回溯法是一种算法思想。

    何为八皇后问题?

    (百度百科)八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当 n = 1 或 n ≥ 4 时问题有解。

    八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。

    艾兹格·迪杰斯特拉在1972年用这个问题为例来说明他所谓结构性编程的能力。
    八皇后问题出现在1990年代初期的著名电子游戏第七访客中。

    解题思想

    我们采用回溯法来解决这个问题。还记得我说的动态穷举法(“剪枝”)?那么我们就开始穷举吧。过程请看下图。八个皇后,每个皇后放一行,那么我们要确定的就是每行皇后要放的列的位置。对于第一行,假设把皇后放在第一列(这里就开始了一个for循环了)。第一步当然满足,然后我们看第二行(又开始一个for循环啦),假设把第二个皇后放在(2,1)(行,列)处,不行(“剪枝”)!那继续for,放在(2,2)处,不行(“剪枝”)!继续for,放在(2,3)处。Bingo!那我们进行第三步,第四步....也许,在第三步当中,执行完第三步的八次for循环后,仍未有合理的答案。那么就得返回第二步了。这时候,把第二个皇后放在(2,4)处。继续......

    (参考http://blog.csdn.net/justme0/article/details/7540425)

             

    接下来,我们就要尝试把这个过程转化成伪代码。

    //寻找当前行的皇后应该位于哪一列
    void FindQueen(row)
    {
      for(int i=0;i<8;i++)
      {
        //1.判断当前是否满足要求
        if(Is_Meet(row,i))
        {
        //2.判断当前是否是最后一行了
          if(最后一行){输出操作,并返回}
        //3.执行下一行匹配
          FindQueen(row+1);
        //4.如果进行到这一步,说明步骤三已经操作完,没有合适结果,需要返回上一步,即执行当前for的下一个循环
        }
      }
    }

    判断是否满足条件

    这里,有一步我们需要再考虑下的,即第1步,如何判断当前插入的皇后满足条件。

    根据国际象棋的规则,不能有两个皇后位于:1)同一列;2)同一对角线。

    1)同一列

    比较好判断,列号相同,即属于同一列;

    2)同一对角线

    有两种位置:正斜对角线和反斜对角线。判断条件分别为:(r1+c1)==(r2+c2),(r1-c1)==(r2-c2)

    将新的皇后位置依次与已经插入过的皇后位置进行比较判断即可。

    具体实现

    看到以上代码,应该有点思路了吧。上具体实现代码。

    bool Is_Meet(int row,int column)
    {
        int c;
        for(int r=0;r<row;r++)
        {
            c=queen[r];
            if(column==c)
                return 0;
            if((row+column)==(c+r))
                return 0;
            if((column-row)==(c-r))
                return 0;
        }
        return 1;
    }
    
    void findQueen(int row)
    {
        for(int c=0;c<8;c++)
        {
            if(Is_Meet(row,c))
            {
                queen[row]=c;
                if(row==7)
                {
                    print();
                    return;
                }
                findQueen(row+1);
            }
            queen[row]=-1;
        }
    }

    为了好玩,简单地改了下,使其可以在控制台动态显示匹配过程。

    #include "iostream"
    #include "string"
    #include <Windows.h>
    using namespace std;
    int queen[8];
    
    void print()
    {
        system("cls");
        cout << "八皇后问题动态演示
    ";
        cout<< "------------------------
    ";
        for (int outer = 0; outer < 8; outer++)
        {
            if(queen[outer]!=-1)
            {
            for (int inner = 0; inner < queen[outer]; inner++)
                cout << " . ";
            cout<<" # ";
            }
            for (int inner = queen[outer] + 1; inner < 8; inner++)
                cout << " . ";
            cout<<endl;
        }
    }
    
    bool Is_Meet(int row,int column)
    {
        int c;
        for(int r=0;r<row;r++)
        {
            c=queen[r];
            if(column==c)
                return 0;
            if((row+column)==(c+r))
                return 0;
            if((column-row)==(c-r))
                return 0;
        }
        return 1;
    }
    
    void findQueen(int row)
    {
        for(int c=0;c<8;c++)
        {
            Sleep(1000);
            print();
            if(Is_Meet(row,c))
            {
                queen[row]=c;
                if(row==7)
                {
                    //print();
                    return;
                }
                findQueen(row+1);
            }
            queen[row]=-1;
        }
    }
    int main()
    {
        memset(queen,-1,8*sizeof(int));//这里是赋-1,故不会出错,要清楚memset是依次对单个字节进行赋值
        findQueen(0);
    }
  • 相关阅读:
    关于Ubuntu中passwd、shadow、group等文件
    Android colors.xml 颜色列表
    【设计】线框图、原型和视觉稿的区别
    【设计】24款线框图相关工具及资源大放送
    【辅助工具】20款优秀的移动产品原型和线框图设计工具(二)
    【辅助工具】20款优秀的移动产品原型和线框图设计工具(一)
    GET RESTful With Python
    VRRP、Track与NQA联动配置举例(Master监视上行链路)
    静态路由、Track与NQA联动配置举例
    ROS-MikroTik-RouterOS-培训认证各种证书
  • 原文地址:https://www.cnblogs.com/lsr-flying/p/4727812.html
Copyright © 2020-2023  润新知