BFS

一、BFS

       BFS,即为宽度优先搜索,思路是先搜索距离初始状态近的状态。按照初始状态->只需一次就可以到达的状态->只需两次就可以。。。。。。

      宽度优先搜索采用了队列的思想

框架:

摘自:https://www.cnblogs.com/zhangchengbing/p/3210362.html

广度优先搜索算法如下:(用 QUEUE)
    (1) 把初始节点S0放入Open表中;
    (2) 如果Open表为空,则问题无解,失败退出;
    (3) 把Open表的第一个节点取出放入Closed表,并记该节点为n;
    (4) 考察节点n是否为目标节点。若是,则得到问题的解,成功退出;
    (5) 若节点n不可扩展,则转第(2)步;
    (6) 扩展节点n,将其子节点放入Open表的尾部,并为每一个子节点设置指向父节点的指针,然后转第(2)步。
 
代码框架:
BFS()
{
初始化队列
最短路径要将每个元素设为INF
while(队列不为空且未找到目标节点)
{
取队首节点扩展,并将扩展出的节点放入队尾;
必要时要记住每个节点的父节点;
}
}

二、例题

例一、迷宫最短路径

题目    给定一个大小为N*M的迷宫,迷宫由通道和墙壁组成,,每一步可以向左右上下四个方向走一步,请计算从出发点到终点最少需要多少步,若不能到达终点则输出‘NO’

n,m<=100

input

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
SW.W.....WW.
W.W.W.....W.
.W.WG.....W.
..W.......W

output

12

题解:因为如果第一步能到达,那么肯定会舍弃第二步,所以可以用bfs算法来解决

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<utility>
#define maxn 110
#define INF 1e6
using namespace std;
typedef pair<int,int> P;
queue<P>que;
char maze[maxn][maxn];//迷宫
int x,y;//迷宫的行数和列数
int d[maxn][maxn];//储存从起点到该点的距离
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};//上下左右移动
int beginx,beginy;//迷宫开始的横纵坐标
int endx,endy;//迷宫结束的横纵坐标

void init()//初始化和输入
{
    while(!que.empty())
       que.pop();
    scanf("%d%d",&x,&y);
    for(int i=0;i<x;i++)
        for(int j=0;j<y;j++)
            d[i][j]=INF;//初始距离为无穷
    for(int i=0;i<x;i++)
        scanf("%s",maze[i]);
    for(int i=0;i<x;i++)
        for(int j=0;j<y;j++)
        {
            if(maze[i][j]=='S')
            {
                beginx=i;
                beginy=j;
            }
            if(maze[i][j]=='G')
            {
                endx=i;
                endy=j;
            }
        }

}

int bfs(int ix,int iy)//bfs
{
    d[ix][iy]=0;
    que.push(P(ix,iy));
    while(!que.empty())
    {
        P q=que.front();//队列的第一个用front
        que.pop();
        int tx=q.first;
        int ty=q.second;
        for(int i=0;i<4;i++)
        {
            int xx=tx+dx[i];
            int yy=ty+dy[i];
            if(xx>=0&&xx<x&&yy>=0&&yy<y)//处在合法的位置
            {
                if(maze[xx][yy]!='W'&&d[xx][yy]==INF)
                {
                    d[xx][yy]=d[tx][ty]+1;
                    if(maze[xx][yy]=='G')
                        return d[xx][yy];
                    que.push(P(xx,yy));
                }
            }
        }
    }
    return d[endx][endy];
}

int main()
{
    init();
    printf("%d\n",bfs(beginx,beginy));
    return 0;
}

 


例二、数字迷宫

描述这有一个迷宫,有N行和M列:
0表示道路,1表示墙。
现在输入一个道路的坐标作为起点,再如输入一个道路的坐标作为终点,问最少走几步才能从起点到达终点?
(注:一步是指从一坐标点走到其上下左右相邻坐标点,如:从(3,1)到(4,1)。)
输入
第一行输入行数和列数,随后输入N行M列数字
输入一个整数n(0<n<=100),表示有n组测试数据;
随后n行,每行有四个整数a,b,c,d(0<=a,b,c,d<=8)分别表示起点的行、列,终点的行、列。
输出
输出最少走几步。
样例输入 
            9 9
1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 1
1 0 0 1 1 0 0 0 1
1 0 1 0 1 1 0 1 1
1 0 0 0 0 1 0 0 1
1 1 0 1 0 1 0 0 1
1 1 0 1 0 1 0 0 1
1 1 0 1 0 0 0 0 1
1 1 1 1 1 1 1 1 1   
2
 3 1  5 7
  3 1  6 7
样例输出
    12
    11
代码:
#include<iostream>
#include<algorithm>
#include<utility>
#include<string>
#include<queue>
#define maxn 105
#define INF 1000000
using namespace std;
typedef pair<int,int> P;
int bx,by;//初始点的坐标
int co,ex,ey;//终点的坐标
int N,M;//行数和列数
int a[maxn][maxn];//记录是否被标记
int s[maxn][maxn];//记录地图
queue<P> que;//bfs的队列
int dx[]= {0,0,1,-1},dy[]= {1,-1,0,0}; //上下左右移动
int bfs()
{
    while(!que.empty())
    {
        P p=que.front();
        que.pop();
        int x=p.first,y=p.second;
        if(x==ex&&y==ey)
            break;
        for(int i=0; i<4; i++)
        {
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=0&&xx<N&&yy>=0&&yy<M&&a[xx][yy]==INF&&s[xx][yy]!=1)
            {
                que.push(P(xx,yy));
                a[xx][yy]=a[x][y]+1;
            }
        }
    }
    return a[ex][ey];
}
int main()
{
    while(cin>>N>>M&&M)
    {
        for(int i=0; i<N; i++)
            for(int j=0; j<M; j++)
                cin>>s[i][j];
        cin>>co;
        while(co--)
        {
            cin>>bx>>by>>ex>>ey;
            while(!que.empty())
                que.pop();//清空队列
            for(int i=0; i<N; i++)
                for(int j=0; j<M; j++)
                    a[i][j]=INF;
            a[bx][by]=0;
            que.push(P(bx,by));
            int ans=bfs();
            cout<<ans<<endl;
        }

    }
    return 0;
}
例题三、奇怪的电梯

题目描述
有一天桐桐做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1≤i≤N)上有一个数字K;(0≤Ki≤N)。电梯只有四 个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5代表了Ki (K1=3,K2=3,…),从一楼开始。在一楼,按“上,”可以到4楼,按“下”是不起作用的,因为没有-2楼。那么,从A楼到B楼至少要按几次按钮 呢?
输入
第1行为三个正整数,表示N,A,B(1≤N≤200,1≤A,B≤N);
第2行为N个正整数,表示Ki。
输出
1行,即最少按键次数,若无法到达,则输出-1。
样例输入
5 1 5
3 3 1 2 5
样例输出
3
题解:因为是每一步只有两种选择,每个楼层只会经历一次,因此可以用bfs

代码:
#include<iostream>
#include<algorithm>
#include<utility>
#include<string>
#include<queue>
#include<cstring>
#define maxn 105
#define INF 1000000
using namespace std;
int a[]= {1,-1};
queue<int>que;
int bf,ef;//起始的楼层,最后的楼层
int N;//楼层数
int k[100],fl[100];
int bfs()
{
    while(!que.empty())
    {
        int p=que.front();//初始的层数
        que.pop();
        if(p==ef)
            break;
        for(int i=0; i<2; i++)
        {
            int f=a[i]*k[p];//移动的步数
            if(p+f>=1&&p+f<=N&&fl[p+f]==0)
            {
                que.push(p+f);
                fl[p+f]=fl[p]+1;
            }
        }
    }
    return fl[ef];
}
int main()
{
    while(cin>>N&&N)
    {
        cin>>bf>>ef;
        memset(fl,0,sizeof(fl));
        for(int i=1; i<=N; i++)
            cin>>k[i];
        while(!que.empty())
            que.pop();//清空队列
        fl[bf]=0;
        que.push(bf);
        int ans=bfs();
        cout<<ans<<endl;
    }
    return 0;
}
例题四、Catch That Cow

题目:Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.

 Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
 Teleporting: FJ can move from any point X to the point 2 × X in a single minute.

If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input

Line 1: Two space-separated integers: N and K
Output

Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
Sample Input

5 17
Sample Output

4
Hint

The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.

题解:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<utility>
#include<cstring>
#define maxn 100000
using namespace std;
queue<int>que;
int N,M;
int a[maxn];
int main()
{
    while(cin>>N>>M)
    {
        memset(a,0,sizeof(a));
        while(!que.empty())
            que.pop();
        que.push(N);
        a[N]=0;
        while(que.size())
        {
            int k=que.front();
            que.pop();
            if(k==M)
                break;
            for(int i=0;i<3;i++)
            {
                int kk;
                if(i==0)
                {
                   kk=k+1;
                   if(kk>=0&&kk<=maxn&&a[kk]==0)
                   {
                       que.push(kk);
                       a[kk]=a[k]+1;
                   }
                }
                if(i==1)
                {
                   kk=k-1;
                   if(kk>=0&&kk<=maxn&&a[kk]==0)
                   {
                       que.push(kk);
                       a[kk]=a[k]+1;
                   }
                }
                if(i==2)
                {
                   kk=k*2;
                   if(kk>=0&&kk<=maxn&&a[kk]==0)
                   {
                       que.push(kk);
                       a[kk]=a[k]+1;
                   }
                }
            }
        }
        cout<<a[M]<<endl;
    }
    return 0;
}

posted @ 2020-07-22 21:36  Joelin12  阅读(213)  评论(0)    收藏  举报