• 回溯算法


    回溯法也称试探法,它的基本思想是:从问题的某一种状态(初始状态)出发,搜索从这种状态出发所能达到的所有“状态”,当一条路走到“尽头”的时候(不能再前进),再后退一步或若干步,从另一种可能“状态”出发,继续搜索,直到所有的“路径”(状态)都试探过。这种不断“前进”、不断“回溯”寻找解的方法,就称作“回溯法”。

    用回溯算法解决问题的一般步骤为:

    1、定义一个解空间,它包含问题的解。

    2、利用适于搜索的方法组织解空间。

    3、利用深度优先法搜索解空间。

    4、利用限界函数避免移动到不可能产生解的子空间。

    问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。

    通常情况下,回溯法是通过递归来实现的,所以需要考虑递归的终止条件。同时当我们一条路走到“尽头”的时候,要后退到上一步,同时要消除当前这一步所产生的影响(一般是某些状态值,这是回溯的重点)。

    回溯本质上是一种穷举法,在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。只不过通常的题目中会有某些条件(比如最大、最小值的限制)可以供我们利用, 来进行剪枝,不去走那些肯定跟最终解没有关系的路径,从而提高效率。
     
    光说不练假把式,下面来看一下,回溯法最经典的问题。

    问题描述:

    八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

     

    问题历史:
    八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。
     
    解法思路:
    (1)先从首位开始检查,如果不能放置,接着检查该行第二个位置,依次检查下去,直到在该行找到一个可以放置一个皇后的地方,然后保存当前状态,转到下一行重复上述方法的检索。
    (2)如果检查了该行所有的位置均不能放置一个皇后,说明上一行皇后放置的位置无法让所有的皇后找到自己合适的位置,因此就要回溯到上一行,重新检查该皇后位置后面的位置。
     
    代码实现:
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int count=0;
    void solve (int linenum,int *LineSet,bool *column,bool *oblique1,bool *xie2,ofstream &os)
    {
        for(int i=0;i<8;i++)
        {
            if(!column[i]&&!oblique1[linenum+i]&&!xie2[linenum-i+7])
            {
                LineSet[linenum]=i;
                column[i]=true;
                oblique1[linenum+i]=true;
                xie2[linenum-i+7]=true;
                if(linenum==7)
                {
                    for(int k=0;k<8;k++)
                    {
                        for(int j=0;j<8;j++)
                        {
                            if(j==LineSet[k])
                            {
                                os<<" Q"; 
                            }else
                            {
                                os<<" +";
                            }
    
                        }
                        os<<endl;
                    }
    
                    count++;
                    os<<"这是第"<<count<<"种结果"<<endl;
                    os<<endl;
                    LineSet[linenum]=999;
                    column[i]=false;
                    oblique1[linenum+i]=false;
                    xie2[linenum-i+7]=false;
                    return;
                }
                else
                {
                    solve(linenum+1,LineSet,column,oblique1,xie2,os);
                    LineSet[linenum]=999;
                    column[i]=false;
                    oblique1[linenum+i]=false;
                    xie2[linenum-i+7]=false;
                    
                }
            }
            
        }
    }
    
    int main()
    {
        int LineSet[8];
        bool column[8];
        bool oblique1[15];
        bool oblique2[15];
        for(int i=0;i<8;i++)
        {
            LineSet[i]=999;
            column[i]=false;
        }
        for(int i=0;i<15;i++)
        {
            oblique1[i]=false;
            oblique2[i]=false;
        }
        ofstream os("result.txt");
        solve(0,LineSet,column,oblique1,oblique2,os);
    }

    结果():

    Q + + + + + + +
    + + + + Q + + +
    + + + + + + + Q
    + + + + + Q + +
    + + Q + + + + +
    + + + + + + Q +
    + Q + + + + + +
    + + + Q + + + +
    这是第1种结果

    Q + + + + + + +
    + + + + + Q + +
    + + + + + + + Q
    + + Q + + + + +
    + + + + + + Q +
    + + + Q + + + +
    + Q + + + + + +
    + + + + Q + + +
    这是第2种结果

    Q + + + + + + +
    + + + + + + Q +
    + + + Q + + + +
    + + + + + Q + +
    + + + + + + + Q
    + Q + + + + + +
    + + + + Q + + +
    + + Q + + + + +
    这是第3种结果

    Q + + + + + + +
    + + + + + + Q +
    + + + + Q + + +
    + + + + + + + Q
    + Q + + + + + +
    + + + Q + + + +
    + + + + + Q + +
    + + Q + + + + +
    这是第4种结果

    + Q + + + + + +
    + + + Q + + + +
    + + + + + Q + +
    + + + + + + + Q
    + + Q + + + + +
    Q + + + + + + +
    + + + + + + Q +
    + + + + Q + + +
    这是第5种结果

    ...

    + + + + + + + Q
    + Q + + + + + +
    + + + + Q + + +
    + + Q + + + + +
    Q + + + + + + +
    + + + + + + Q +
    + + + Q + + + +
    + + + + + Q + +
    这是第90种结果

    + + + + + + + Q
    + + Q + + + + +
    Q + + + + + + +
    + + + + + Q + +
    + Q + + + + + +
    + + + + Q + + +
    + + + + + + Q +
    + + + Q + + + +
    这是第91种结果

    + + + + + + + Q
    + + + Q + + + +
    Q + + + + + + +
    + + Q + + + + +
    + + + + + Q + +
    + Q + + + + + +
    + + + + + + Q +
    + + + + Q + + +
    这是第92种结果

    结果比较多,省略了一些,有兴趣可以自己编译运行一下程序代码,查看所有92个解。

  • 相关阅读:
    Cookie和Session的那些事儿
    【IScroll深入学习】解决IScroll疑难杂症
    使用 iscroll 实现焦点图无限循环
    jquery.mobiscroll仿Iphone ActionSheet省市区联动
    mobiscroll之treelist使用
    jQuery.extend 函数详解
    jQuery插件开发精品教程,让你的jQuery提升一个台阶
    用js实现动画效果核心方式
    js特效,加速度,图标跳动
    详解用CSS3制作圆形滚动进度条动画效果
  • 原文地址:https://www.cnblogs.com/scarecrow-blog/p/3927585.html
Copyright © 2020-2023  润新知