zoukankan      html  css  js  c++  java
  • 关于dbfs原理 相对于bfs的复杂度优化及应用

    (关于dbfs,A*,迭代加深及idA*的学习借鉴于北大暑假ACM课)

    dbfs即双向广搜,从起点终点同时bfs,直到两个bfs有了交点,就找到了答案。 

    dbfs对单向bfs在搜索广度上有明显的减少,在时间及空间复杂度上都有极大的优化。

    举例:

    假设1个结点能扩展出n个结点,单向搜索要m层能找到答案,那 么扩展出来的节点数目就是: (1-n^ m)/(1-n)

    而dbfs节点数目为2 * (1-n^m/2)/(1-n)

    通过八数码问题能极大的体现出双向广搜的优越性

    poj1077 bfs 735ms 2892K dbfs 32ms 1040K

    接下来通过一道例题模拟dbfs思路

    当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能
    得到迷宫地图,事情就会变得非常简单。
    假设你已经得到了一个 n × m 的迷宫的图纸,请你找出从起点到出口的最短路

    第一行是两个整数 n 和 m,表示迷宫的行数和列数。
    接下来 n 行,每行一个长为 m 的字符串,表示整个迷宫的布局。字符. 表示空地,
    # 表示墙,S 表示起点,T 表示出口。


    输出从起点到出口最少需要走的步数

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define maxn 110
    #include<queue>
    using namespace std;
    queue<int> q[2];
    int u[5]={0,0,1,-1},p[5]={1,-1,0,0};
    int n,m;
    int wall[maxn*maxn],vis[2][maxn*maxn],inque[2][maxn*maxn],dis[maxn*maxn];
    char map[maxn][maxn];
    int cal(int x,int y){  return x*m+y; }//由于使用队列,将二维转化一维
    int ok(int x,int y)//判断越界问题
    {
        if(x>=0&&y>=0&&x<n&&y<m)return true;
        return false;
    }
    int dbfs(int st,int ed)
    {
        memset(dis,0x7f,sizeof(dis));
        dis[st]=0;
        dis[ed]=0;
        q[0].push(st);//将起点存入队列1,终点存入队列2
        q[1].push(ed);
        inque[0][st]=1;//记录是否入队
        inque[1][ed]=1;
        while(!q[1].empty()&&!q[0].empty())//两队都不为空
        {
            int id=q[0].size()>q[1].size();//为使相遇点尽量靠近中间点,每次扩展队内元素少的一边
            int d=q[id].front();
            q[id].pop();
            inque[id][d]=0;//出队
            int x=d/m;//求其二维坐标
            int y=d%m;
            for(int i = 0 ; i < 4 ; ++i)
            {
                int dx=x+u[i],dy=y+p[i];
                int dd=cal(dx,dy);
                if(!ok(dx,dy)||wall[dd])continue;
                if(vis[id^1][dd]||inque[id^1][dd])return dis[d]+dis[dd]+1;//相遇点,返回dis
                if(dis[dd]>dis[d]+1)//松弛
                {
                    dis[dd]=dis[d]+1;
                    if(!inque[id][dd])
                    {
                        inque[id][dd]=1;
                        q[id].push(dd);
                    }
                }
            }
            vis[id][d]=1;   //放入closed表内 
        }
        int id=q[0].empty();//找到队内不为空的一队
        while(!q[id].empty())
        {
            int d=q[id].front();
            q[id].pop();
            inque[id][d]=0;
            int x=d/m;
            int y=d%m;
            for(int i = 0 ; i < 4 ; ++i)
            {
                int dx=x+u[i],dy=y+p[i];
                int dd=cal(dx,dy);
                if(!ok(dx,dy)||wall[dd])continue;
                if(vis[id^1][dd]||inque[id^1][dd])return dis[d]+dis[dd]+1;
                if(dis[dd]>dis[d]+1)
                {
                    dis[dd]=dis[d]+1;
                    if(!inque[id][dd])
                    {
                        inque[id][dd]=1;
                        q[id].push(dd);
                    }
                }
            }
            vis[id][d]=1;    
        }
    }
    int main()
    {
        //freopen("maze.in","r",stdin);
        //freopen("maze.out","w",stdout);
        int s,t;
        scanf("%d%d",&n,&m);
        for(int i = 0 ; i < n ; ++i)
            scanf("%s",map[i]);
        for(int i = 0 ; i < n ; ++i)
            for(int j = 0 ; j < m ; ++j)
            {
                if(map[i][j]=='S')s=cal(i,j);
                else if(map[i][j]=='T')t=cal(i,j);
                else if(map[i][j]=='#')wall[cal(i,j)]=1;
            }
        printf("%d",dbfs(s,t));
        return 0;
    }

    inque 相当于open表

    vis 相当于 closed 表

    双向广搜适用于大多数bfs可解决的问题,但还是要具体问题具体分析,比如 抓住那头牛 由于终点走向起点时可以走x/2,与正向遍历相反,用dbfs就不太好解决了。

  • 相关阅读:
    POJ 2236 Wireless Network(并查集)
    POJ 2010 Moo University
    POJ 3614 Sunscreen(贪心,区间单点匹配)
    POJ 2184 Cow Exhibition(背包)
    POJ 1631 Bridging signals(LIS的等价表述)
    POJ 3181 Dollar Dayz(递推,两个long long)
    POJ 3046 Ant Counting(递推,和号优化)
    POJ 3280 Cheapest Palindrome(区间dp)
    POJ 3616 Milking Time(dp)
    POJ 2385 Apple Catching(01背包)
  • 原文地址:https://www.cnblogs.com/fujudge/p/7359039.html
Copyright © 2011-2022 走看看