Breadth First Search (BFS)入门

BFS思想:

从初始结点开始,应用算符生成第一层结点,检查目标结点是否在这些后继结点中,若没有,再用产生式规则将所有第一层的结点逐一扩展,得到第二层结点,并逐一检查第二层结点中是否包含目标结点。若没有,再用算符逐一扩展第二层所有结点……,如此依次扩展,直到发现目标结点为止 。

BFS就是对一个点的所有可以走的情况同时访问,一个层次一个层次地访问,所以称为宽度优先搜索(Breadth First Search)

而DFS是对一个点的可以走的一种情况进行访问,如果这种情况的下一个点还能走的话,在对这个点进行下一次的访问,这个是一个分支一个分支地访问,所以称为深度优先搜索(Depth First Search );

现在用图来讲一下哈:比如对于这个图来说:

《Breadth First Search (BFS)入门》

BFS:如果A是起点的话,那么访问顺序是: A  =》 B  ,C   =》D, E, F,而模拟这个过程的就是queue队列了,先把这一层的元素保存在队列之中,然后再逐个对队列里的元素进行操作。

DFS:如果derict数组的方向是左边的话,那么访问顺序是A =》B = 》D =》 E  =》 C =》F,就是想把一个分支全部访问完了,在访问下一个分支。

POJ3984  迷宫问题

这个题是经典的BFS,当初一直不想去整这种东西,这个题的话就是在访问的时候用pre记录一下该节点的上一个点,然后输出的时候利用一下stack栈的FILO就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>

using namespace std;
const int N = 5;
const int maxn = 100000+10;
int derict[4][2] =
{
    0,1,
    0,-1,
    1,0,
    -1,0,
};
int maze[10][10];
struct Node
{
    int x;
    int y;
    int pre;
}nod[maxn];//节点的坐标是x *N +y
bool vis[N][N];
void print()
{
    int point = 4 *5 +4;
    stack<Node>s;
    for(int i=point ; ; i= nod[i].pre)
    {
        s.push(nod[i]);
//        cout<<"("<<nod[i].x<<", "<<nod[i].y<<")"<<endl;
        if(i==0)
            break;
    }
    while(! s.empty())
    {
        cout<<"("<<s.top().x<<", "<<s.top().y<<")"<<endl;
        s.pop();
    }
}
void bfs(int x,int y)
{
    int point = x *N +y;
    nod[point].x = x;
    nod[point].y = y;
    nod[point].pre = -1;
    vis[x][y] = true;
    queue<Node>q;
    q.push(nod[point]);
    while(! q.empty())
    {
        Node temp = q.front();
        q.pop();

        for(int i=0 ;i < 4;i++)
        {
            int xx= temp.x +derict[i][0];
            int yy= temp.y +derict[i][1];
            if(xx>=0 && xx<N && yy>=0 &&yy <N && !vis[xx][yy] && maze[xx][yy]== 0)
            {
                vis[xx][yy] = true;
                point= xx*5 + yy;
                nod[point].x = xx;
                nod[point].y = yy;
                nod[point].pre = temp.x * 5 + temp.y;
                q.push(nod[point]);
                if(xx== 4 && yy== 4)
                {
                    print();
                    return ;
                }
            }
        }
    }
}
int main()
{
    memset(vis,false,sizeof(vis));
    for(int i=0;i <N;i++)
    {
        for(int j=0;j<N ;j++)
        {
            scanf("%d",&maze[i][j]);
        }
    }
    bfs(0,0);
    return 0;
}

HDU1548 A Strong Lift

这个题的意思就是从start这层坐电梯到destination这一层,不过电梯在每层的有一个k[i],代表在这层只能上升或者下降k[i]层,所以用一个time数组记录一下按按钮的次数,直接把所有的情况走一遍就好了,到达了这层的话就输出,之后直接输出time[destination],就是按了多少次。当初错了一发,所以就用pre数组记录了一下,输出了一下,发现没有错误,后面才发现没有判断能不能到达的情况,所以》》》》

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>

using namespace std;
const int N = 5;
const int maxn = 100000+10;
int k[maxn];
int n,start,destination;
int ans;
bool vis[maxn];
int time[maxn];
int pre[maxn];
void BFS()
{
    queue<int >q;
    time[start] = 0;
    q.push(start);
    pre[start] = -1;
    vis[start]= true;
    while(! q.empty())
    {
        int  temp = q.front();

        q.pop();
        int xx = temp + k[temp];
        int yy = temp - k[temp];
        if(xx>= 1 && xx <= n && !vis[xx])
        {
            pre[xx] = temp;
            time[xx] = time[temp] +1;
            if(xx == destination )
                return ;
            vis[xx] = true;
            q.push(xx);
        }
        if(yy >= 1 && yy <= n && !vis[yy])
        {
            pre[yy] =temp;
            vis[yy ] = true;
            time[yy] = time[temp] +1;
            if(yy == destination )
                return ;
            q.push(yy);
        }
    }
    return ;
}
int main()
{
    while(~scanf("%d",&n) && n)
    {
        memset(vis,false,sizeof(vis));
        memset(time,0,sizeof(time));
        scanf("%d%d",&start,&destination);
        for(int i= 1;i <= n;i++)
            scanf("%d",&k[i]);
        BFS();
//        for(int i=destination ; i!=  - 1;i = pre[i])
//        {
//            cout<<i<<" ";
//        }
//        cout<<endl;
//        for(int i= 1;i <=n ;i++)
//        cout<<time[i]<<" ";
//        cout<<endl;
        if(start != destination && time[destination] ==0)//判断是否能够到达。
        {
            cout<<"-1"<<endl;
            continue;
        }
        cout<<time[destination]<<endl;
    }
    return 0;
}

hdu2717Catch That Cow

不知道为什么同样的代码在hdu上能过,在poj上却runtime error,我觉得肯定是我的代码有点问题吧,不然怎么会在poj上过不了呢,不过找了半天没找到。但我又想了一下,同样的题hdu能过,是不是hdu和poj的数据不一样呢?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>

using namespace std;
const int N = 5;
const int maxn = 100000+10;
int start,destination;
int time[maxn];
bool vis[maxn];
void BFS()
{
    queue<int >q;
    time[start] =0;
    q.push(start);
    vis[start] = true;
    while(! q.empty())
    {
        int temp=q.front();
        q.pop();
        int x = temp +1,y =temp-1,z=temp*2;
        if(! vis[x] && x>=0 && x< maxn)
        {
            q.push(x);
            time[x] =time[temp] +1;
            if(x == destination)
                return ;
            vis[x] = true;
        }
        if(! vis[y] && y>=0 && y<maxn)
        {
            q.push(y);
            time[y] =time[temp] +1;
            if(y == destination)
                return ;
            vis[y] = true;
        }
        if(! vis[z] && z>=0 && z<maxn)
        {
            q.push(z);
            time[z] =time[temp] +1;
            if(x == destination)
                return ;
            vis[z] = true;
        }
    }
}

int main()
{
    int n,m;
    while(~scanf("%d%d",&start,&destination))
    {
        memset(vis,false,sizeof(vis));
        memset(time,0,sizeof(time));
        BFS();
        cout<<time[destination]<<endl;
    }
    return 0;
}

POJ2251 Dungen Master

题意:求从S到E的时间
开始写这个代码的时候还不知道怎么输入三维字符串,看了一下别人怎么输入就知道了,这个题虽然是三维的一个搜索,但是相对于二维的就相差了一个derict数组改变了一下,然后加上一个time[ ]数组,就行了,也是一个经典的Breadth First Search 了。


#include <iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=40;
char ss[maxn][maxn][maxn];
bool vis[maxn][maxn][maxn];
struct Node
{
    int c,x,y;
}s,e;//s代表start起点,e代表end终点,c,x,y分别代表层和坐标
int times[maxn][maxn][maxn];
int derict[6][3]=
{
    -1,0,0,
    1,0,0,
    0,1,0,
    0,-1,0,
    0,0,-1,
    0,0,1,
};//6个方向
int c,n,m;
void bfs()
{
    vis[s.c][s.x][s.y] = true;
    times[s.c][s.x][s.y] = 0;
    queue<Node>q;
    q.push(s);
    while( ! q.empty())
    {
        Node t=q.front();
//        cout<<t.c<<" "<<t.x<<" "<<t.y<<endl;
        q.pop();
        for(int i=0;i<6;i++)
        {
            int xx = t.c+derict[i][0];
            int yy = t.x +derict[i][1];
            int zz = t.y +derict[i][2];
            if(xx >=0 && xx<c && yy>=0 && yy<n && zz>=0 && zz<m && !vis[xx][yy][zz] && (ss[xx][yy][zz] =='.' || ss[xx][yy][zz]== 'E') )
            {
                Node temp;
                temp.c= xx;
                temp.x=yy;
                temp.y=zz;
                times[xx][yy][zz] = times[t.c][t.x][t.y] +1;
                if(xx == e.c && yy == e.x && zz == e.y)
                    return ;
                vis[xx][yy][zz] = true;
                q.push(temp);
            }
        }
    }
}
int main()
{

    while(~scanf("%d%d%d",&c,&n,&m) && (n || m|| c))
    {
        memset(times,0,sizeof(times));
        memset(vis,false,sizeof(vis));
        for(int i=0;i<c;i++)
        {
            for(int j=0;j<n;j++)
            {
                scanf("%s",ss[i][j]);
                for(int x=0;x<m;x++)
                {
                    if(ss[i][j][x] == 'S')
                    {
                        s.c=i;
                        s.x=j;
                        s.y=x;
                    }
                    if(ss[i][j][x] =='E')
                    {
                        e.c=i;;
                        e.x=j;
                        e.y=x;
                    }
                }
            }
        }
//        cout<<s.c<<" "<<s.x<<" "<<s.y<<endl;
//        cout<<e.c<<" "<<e.x<<" "<<e.y<<endl;
        bfs();
//        for(int i=0;i<c;i++)
//        {
//            for(int j=0;j<n ;j++)
//            {
//                for(int x=0;x<m;x++)
//                {
//                    cout<<times[i][j][x]<<" ";
//                }
//                cout<<endl;
//            }
//            cout<<endl;
//        }
        if(!(s.c==e.c && s.x==e.x && s.y==s.y))
        {
            if(!times[e.c][e.x][e.y])//判断是不是没有找到情况,这种的情况出现的条件是times[终点]==0 &&终点不等于起点 
            {
                cout<<"Trapped!"<<endl;
            }
            else cout<<"Escaped in "<<times[e.c][e.x][e.y]<<" minute(s)."<<endl;
        }
        else cout<<0<<endl;
    }
    return 0;
}

Find a way hdu 2612



这个题开始不知道怎么也过不了,后面重写一遍就过了,。。,

BFS的思路,然后就是每个人到每个@的时间用数组记录下来,然后之后进行比较;

#include<iostream>
#include<cstring>
#include<queue>
#include<string>
#include<cstdio>
using namespace std;
const int maxn=1000;

char s[maxn][maxn];
bool vis[maxn][maxn];
int time1[maxn][maxn];
int time2[maxn][maxn];
int n,m;

int derict[4][2]=
{
    -1,0,
    1,0,
    0,-1,
    0,1,
};
struct Node
{
    int x;
    int y;
}M,Y;

void BFS1()
{
    vis[Y.x][Y.y] = true;
    queue<Node>q;
    q.push(Y);
    time1[Y.x][Y.y] = 0;
    while(! q.empty())
    {
        Node t= q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int xx = t.x + derict[i][0];
            int yy = t.y + derict[i][1];
            if(xx>=0 && xx<=n && yy>=0 && yy<m && !vis[xx][yy] && s[xx][yy]!='#')
            {
                Node temp;
                temp.x = xx;
                temp.y = yy;
                time1[xx][yy] = time1[t.x][t.y] + 1;
                vis[xx][yy] = true;
                q.push(temp);
            }
        }
    }
    return ;
}
void BFS2()
{
    vis[M.x][M.y] = true;
    queue<Node>q;
    q.push(M);
    time2[M.x][M.y] = 0;
    while(! q.empty())
    {
        Node t= q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int xx = t.x + derict[i][0];
            int yy = t.y + derict[i][1];
            if(xx>=0 && xx<=n && yy>=0 && yy<m && !vis[xx][yy] && s[xx][yy]!='#')
            {
                Node temp;
                temp.x = xx;
                temp.y = yy;
                time2[xx][yy] = time2[t.x][t.y] + 1;
                vis[xx][yy] = true;
                q.push(temp);
            }
        }
    }
    return ;
}
int main()
{
    while(~ scanf("%d%d",&n,&m))
    {
        memset(vis,false,sizeof(vis));
        memset(time1,0,sizeof(time1));
        memset(time2,0,sizeof(time2));
        for(int i=0;i<n;i++)
        {
            scanf("%s",s[i]);
            for(int j=0;j<m;j++)
            {
                if(s[i][j] == 'Y')
                {
                    Y.x =i;
                    Y.y =j;
                }
                if(s[i][j] == 'M')
                {
                    M.x = i;
                    M.y = j;
                }
            }
        }
        BFS1();
        memset(vis,false,sizeof(vis));
        BFS2();
        long long  ans=100000000;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(s[i][j] == '@')
                {
                    if(time1[i][j] + time2[i][j] <ans)
                    {
                        ans=time1[i][j] + time2[i][j];
                    }
                }
            }
        }
        cout<<ans*11<<endl;
    }
    return 0;
}

走迷宫






题意:

从左上角到右下角的最短的时间;用一个times数组记录一下就行了。

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn= 10000+10;
int n,m;
char s[maxn][maxn];
bool vis[maxn][maxn];
int times[maxn][maxn];
int derict[4][2]=
{
    -1,0,
    1,0,
    0,-1,
    0,1,
};
struct Node
{
    int x;
    int y;
};
void BFS()
{
    vis[0][0] = true;
    queue<Node>q;
    Node tt ;
    tt.x = 0;
    tt.y = 0;
    q.push(tt);
    times[0][0] = 0;
    while(! q.empty())
    {
        Node t;
        t = q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int xx = t.x + derict[i][0];
            int yy = t.y + derict[i][1];
            if(xx>=0 && xx<n && yy>=0 && yy<m && !vis[xx][yy] && s[xx][yy] == '.')
            {
                Node temp;
                temp.x =xx;
                temp.y =yy;
                q.push(temp);
                times[xx][yy] = times[t.x][t.y] + 1;
                vis[xx][yy] = true;
                if(xx == n-1 && yy == m-1)
                {
                    return ;
                }
            }
        }
    }
}
int main()
{
   while(~ scanf("%d%d",&n,&m))
   {
       memset(vis,false,sizeof(vis));
       memset(times,0,sizeof(times));

       for(int i=0;i<n;i++)
       {
           scanf("%s",s[i]);
       }
       BFS();
       cout<<times[n-1][m-1]+1<<endl;
   }
   return 0;
}

跳马问题

题意就是一个象棋中的马从一个点跳到另一个点最少要多少时间?

与普通的BFS不同的是:马的走法有8个日的方向;

#include<bits/stdc++.h>
using namespace std;

int a,b,c,d;
int derict[8][2]=
{
    1,2,
    2,1,
    2,-1,
    1,-2,
    -1,-2,
    -2,-1,
    -2,1,
    -1,2,
};
bool vis[100][100];
int times[100][100];
struct Node
{
    int x,y;
};
void BFS()
{
   Node tt;
   tt.x =a;
   tt.y =b;
   queue<Node>q;
   vis[a][b] = true;
   times[a][b] = 0;
   q.push(tt);
   while(! q.empty())
   {
       Node t;
       t=q.front();
       q.pop();
       for(int i=0;i<8;i++)
       {
           int xx= t.x+derict[i][0];
           int yy =t.y+derict[i][1];
           if(xx >=0 &&xx<=9 && yy>=0 && yy<=8 && !vis[xx][yy] )
           {
               Node temp;
               temp.x = xx;
               temp.y = yy;
               vis[xx][yy] = true;
               times[xx][yy] = times[t.x][t.y] + 1;
               q.push(temp);
               if(xx == c && yy == d)
                return ;
           }
       }
   }
}
int main()
{

    while(~ scanf("%d%d%d%d",&a,&b,&c,&d))
    {
        memset(vis,false,sizeof(vis));
        memset(times,0,sizeof(times));
        BFS();
        cout<<times[c][d];
    }
    return 0;
}

    原文作者:BFS
    原文地址: https://blog.csdn.net/xiaolonggezte/article/details/52197674
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞