• 广搜


    广搜

    第一节:广度优先搜索的过程 

    广度优先搜索算法(又称宽度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。

    广度优先算法的核心思想是:从初始节点开始,应用算符生成第一层节点,检查目标节点是否在这些后继节点中,若没有,再用产生式规则将所有第一层的节点逐一扩展,得到第二层节点,并逐一检查第二层节点中是否包含目标节点。若没有,再用算符逐一扩展第二层的所有节点……,如此依次扩展,检查下去,直到发现目标节点为止。即

         ⒈从图中的某一顶点V0开始,先访问V0

         ⒉访问所有与V0相邻接的顶点V1V2......Vt

         ⒊依次访问与V1V2......Vt相邻接的所有未曾访问过的顶点;

         ⒋循此以往,直至所有的顶点都被访问过为止。

         这种搜索的次序体现沿层次向横向扩展的趋势,所以称之为广度优先搜索。

    第二节:广度优先搜索算法描述:

    int bfs()

    {初始化,初始状态存入队列;

    队列首指针head=0; 尾指针tail=1

    do

     {

        指针head后移一位,指向待扩展结点;

        for (int i=1;i<=max;++i)                  //max为产生子结点的规则数

          if (子结点符合条件)

             { tail指针增1,把新结点存入列尾;

                if (新结点与原已产生结点重复) 删去该结点(取消入队,tail1;

                Else if (新结点是目标结点) 输出并退出;}

    }while(head<tail);                       //队列为空}

    第三节:广度优先搜索注意事项:   

    1、每生成一个子结点,就要提供指向它们父亲结点的指针。当解出现时候,通过逆向跟踪,找到从根结点到目标结点的一条路径。当然不要求输出路径,就没必要记父亲。

    2、生成的结点要与前面所有已经产生结点比较,以免出现重复结点,浪费时间和空间,还有可能陷入死循环。

    3、如果目标结点的深度与“费用”(如:路径长度)成正比,那么,找到的第一个解即为最优解,这时,搜索速度比深度搜索要快些,在求最优解时往往采用广度优先搜索;如果结点的“费用”不与深度成正比时,第一次找到的解不一定是最优解。

    4、广度优先搜索的效率还有赖于目标结点所在位置情况,如果目标结点深度处于较深层时,需搜索的结点数基本上以指数增长。

    八数码难题回顾一下

    八数码

    题目描述

    3×3的棋盘上,摆有八个棋子,每个棋子上标有18的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

    输入格式:

    输入初始状态,一行九个数字,空格用0表示

    输出格式:

    只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

    【代码实现】:

    #include<iostream>

    #include<map>

    #include<queue>

    #include<algorithm>

    #define ll long long

    //在这里看到一种很骚的操作:直接把int定义成long longmain函数用signed类型--麻麻再也不怕我忘开long long了!

    using namespace std;

    const ll dx[]={-1,0,0,1},dy[]={0,-1,1,0};//转移数组;

    ll n;

    int  main()

    {

        cin>>n;

        queue<ll> q;

        q.push(n);

        map<ll,ll> m;

        m[n]=0;

        while(!q.empty())

        {

            int u=q.front(); //初始状态入队列

            int c[3][3],f=0,g=0,n=u;q.pop();

            if(u==123804765)break;

            for(ll i=2;i>=0;i--)

                for(ll j=2;j>=0;j--)

                {

                    c[i][j]=n%10,n/=10;

                    if(!c[i][j])f=i,g=j;

                }

            for(ll i=0;i<4;i++)

            {

                ll nx=f+dx[i],ny=g+dy[i],ns=0;

                if(nx<0||ny<0||nx>2||ny>2)continue; //越界就不执行

                swap(c[nx][ny],c[f][g]);

                for(ll i=0;i<3;i++)

                    for(ll j=0;j<3;j++)ns=ns*10+c[i][j];//矩阵转数列

                if(!m.count(ns))

                {

                    m[ns]=m[u]+1;

    //map去重的同时顺便统计到达这个状态所需的步数

                    q.push(ns);

                }

                swap(c[nx][ny],c[f][g]);//状态复原

            }

        }

        cout<<m[123804765]<<endl; // map的下标直接用数列表示

        return 0;

    }

    【总结】:

    1. BfsDfs说它会比Dfs解决最优解问题更快速
    2. Dfs反对说,你消耗的空间太大了,你看我的只是可恶的超时而已
    3. 还有你的判重也是一个不可忽视的不利因素
    4. 双向Bfs可以节省空间哟
    5. STL屁颠屁颠跑过来说,mapqueue就送给你Bfs
    6. HashBfs说有麻烦找哈神,啦啦啦啦

    感谢各位与信奥一本通的鼎力相助!

  • 相关阅读:
    Web基础 网页的血肉CSS
    18
    19
    20
    17
    16
    15
    13
    14
    12
  • 原文地址:https://www.cnblogs.com/SeanOcean/p/10975602.html
Copyright © 2020-2023  润新知