• ACM-BFS之Open the Lock——hdu1195(双向BFS)


    这道题的0基础版本号,暴力BFS及题目详情请戳:http://blog.csdn.net/lttree/article/details/24658031


    上回书说道,要用双向BFS来尝试一下。

    最终AC了,

    双向BFS,就是从两个点寻找一个共同的中间点。

    然后把各自到这个中间点的步数加起来,及为最短步数。

    肯定有人问了。双向BFS有啥优点捏?

    鄙人,有图有真相!

    单BFS:


    双向BFS:


    发现了不?

    尤其是随着搜索广度的增大。那个范围是相当di啊!


    双向BFS做法事实上不难,两个队列。

    一个从头開始搜。一个从尾開始搜。

    可是要注意一点,要逐层搜索。不要逐点搜索呀~

    要在 正向的同一层搜索完后,再去搜索反向的对应层!

    什么叫逐层搜索呢?

    对于这道题而言,VIS数组须要记录到达该点的步数,

    对于每层搜索要把,同一步数的点全出队列遍历一遍,再进行反向搜索。

    OK。这是对于这道题的双向广搜代码(感觉就是把两个广搜叠起来就OK了)


    /**************************************
    ***************************************
    *        Author:Tree                 *
    *From  :http://blog.csdn.net/lttree  *
    * Title : Scrambled Polygon           *
    *Source: hdu 1195                     *
    * Hint  : 双向BFS                     *
    ***************************************
    **************************************/
    
    #include <iostream>
    #include <string.h>
    #include <queue>
    using namespace std;
    struct VIS
    {
        int flag,step;
    }vis[10001];
    struct Key
    {
        int k[4],step;
        friend bool operator <(Key a,Key b)
        {
            return a.step<b.step;
        }
    };
    int ini[4],ans[4],dis[2]={-1,1};
    int solu[9]={9,1,2,3,4,5,6,7,8};
    bool judge(Key a)
    {
        for(int i=0;i<4;++i)
            if( a.k[i]!=ans[i] )
                return false;
        return true;
    }
    // 用来做VIS数组
    int total(Key a)
    {
        int i,sum;
        sum=0;
        for(i=0;i<4;++i)
            sum=sum*10+a.k[i];
        return sum;
    }
    int bfs(void)
    {
        memset(vis,0,sizeof(vis));
        queue <Key> q;
        queue <Key> p;
        Key pre,lst;
        int i,t,sum,sp=0;
    
        // 初始化。。。

    for(i=0;i<4;++i) pre.k[i]=ini[i]; sum=total(pre); vis[sum].flag=1; vis[sum].step=0; pre.step=0; q.push(pre); for(i=0;i<4;++i) lst.k[i]=ans[i]; sum=total(lst); vis[sum].flag=2; vis[sum].step=0; lst.step=0; p.push(lst); while( !q.empty() && !p.empty() ) { // 为了遍历每一层的情况,所以用sp来控制层数 // 正向搜索 while( q.front().step==sp ) { pre=q.front(); q.pop(); for(i=0; i<4; ++i) { if( pre.k[i]!=ans[i] ) { for(t=0; t<2; ++t) { lst=pre; lst.k[i]=solu[(pre.k[i]+dis[t])%9]; sum=total(lst); lst.step=pre.step+1; if( vis[sum].flag==1 ) continue; if( vis[sum].flag==2 ) return lst.step+vis[sum].step; vis[sum].flag=1; vis[sum].step=lst.step; q.push(lst); } } } for(i=0; i<3; ++i) { lst=pre; lst.k[i]=pre.k[i+1]; lst.k[i+1]=pre.k[i]; sum=total(lst); lst.step=pre.step+1; if( vis[sum].flag==1 ) continue; if( vis[sum].flag==2 ) return lst.step+vis[sum].step; vis[sum].flag=1; vis[sum].step=lst.step; q.push(lst); } } // 反向搜索 while( p.front().step==sp ) { pre=p.front(); p.pop(); for(i=0; i<4; ++i) { if( pre.k[i]!=ini[i] ) { for(t=0; t<2; ++t) { lst=pre; lst.k[i]=solu[(pre.k[i]+dis[t])%9]; sum=total(lst); lst.step=pre.step+1; if( vis[sum].flag==2 ) continue; if( vis[sum].flag==1 ) return lst.step+vis[sum].step; vis[sum].flag=2; vis[sum].step=lst.step; p.push(lst); } } } for(i=0; i<3; ++i) { lst=pre; lst.k[i]=pre.k[i+1]; lst.k[i+1]=pre.k[i]; sum=total(lst); lst.step=pre.step+1; if( vis[sum].flag==2 ) continue; if( vis[sum].flag==1 ) return lst.step+vis[sum].step; vis[sum].flag=2; vis[sum].step=lst.step; p.push(lst); } } ++sp; } } int main() { int i,s,test; char c; cin>>test; while( test-- ) { // 输入数据 for(i=0;i<4;++i) { cin>>c; ini[i]=c-'0'; } for(i=0;i<4;++i) { cin>>c; ans[i]=c-'0'; } s=bfs(); cout<<s<<endl; } return 0; }




  • 相关阅读:
    渗透脚本快速生成工具Intersect
    Visual Studio 2017创建XAML文件
    Windows命令远程执行工具Winexe
    解决Visual Studio 2017隐藏“高级保存选项”命令
    Web应用扫描测试工具Vega
    网易轮播图
    Dom
    通过克隆实现无缝滚动轮播图
    函数
    boostrap
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/7144281.html
Copyright © 2020-2023  润新知