一些BFS题集

2 篇文章 0 订阅

一些BFS题集

A计划

可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验。魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老。年迈的国王正是心急如焚,告招天下勇士来拯救公主。不过公主早已习以为常,她深信智勇的骑士LJ肯定能将她救出。  现据密探所报,公主被关在一个两层的迷宫里,迷宫的入口是S(0,0,0),公主的位置用P表示,时空传输机用#表示,墙用*表示,平地用.表示。骑士们一进入时空传输机就会被转到另一层的相对位置,但如果被转到的位置是墙的话,那骑士们就会被撞死。骑士们在一层中只能前后左右移动,每移动一格花1时刻。层间的移动只能通过时空传输机,且不需要任何时间。

Input

输入的第一行C表示共有C个测试数据,每个测试数据的前一行有三个整数N,M,T。 N,M迷宫的大小NM(1 <= N,M <=10)。T如上所意。接下去的前NM表示迷宫的第一层的布置情况,后N*M表示迷宫第二层的布置情况。

Output

如果骑士们能够在T时刻能找到公主就输出“YES”,否则输出“NO”。

Sample Input

15 5 14S#..#............#.

..*.P#.*..***.....*.*.#..

Sample Output

YES

 

思路

BFS走迷宫问题,且是张三维地图(有两层)

可以预先处理必死情况,也就是传送门传到传送门,传送门传到墙,把这两种情况的两层迷宫上的点都改为墙就好了。

注意

上下层切换可以借助如下操作

newF^=1;//异或运算换层

超时就剪枝

if(top.step==maxTime+1)//整个队列全超时
    return false;

如果是按行读入数据,记得吃掉不必要的换行符

代码及注释

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
struct shit
{
    int x,y,f;
    int step;
}temp,P,S;
int n,m,maxTime;
int newF;
int newX;
int newY;
char maze[2][15][15];//地图邻接矩阵
int inq[2][15][15];//标记是否在队列
//四个方向
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};
//判断位置(x,y)是否能走
int judge(int f,int x,int y)//能否走
{
    if(x<0||y<0||x>=n||y>=m)
        return 0;
    //是否在传送门上
    if(maze[f][x][y]=='#')
    {
        newF^=1;//异或运算换层
        f^=1;
    }
    if(maze[f][x][y]=='*')//与前者顺序不能反,不然数组溢出
        return 0;
    if(inq[f][x][y])
        return 0;
    return 1;
}
void remake()//预先处理死路
{
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            if(maze[0][i][j]=='#'&&maze[1][i][j]=='#')//双传送门无限叠加至光速!
            {
                maze[0][i][j]=maze[1][i][j]='*';//这两传送门变成墙
            }
            if((maze[0][i][j]=='#'&&maze[1][i][j]=='*')||(maze[0][i][j]=='*'&&maze[1][i][j]=='#'))//传送到墙上
            {
                maze[0][i][j]=maze[1][i][j]='*';//这两传送门变成墙
            }
        }
}
bool BFS()
{
    queue<shit> q;//定义shit型队列
    q.push(S);//起点入队
    //printf("S.step:%d,S.f:%d,S.x:%d,S.y:%d\n",S.step,S.f,S.x,S.y);
    while(!q.empty())
    {
        shit top=q.front();//取队列首
   //printf("top.step:%d,top.f:%d,top.x:%d,top.y:%d\n",top.step,top.f,top.x,top.y);
        q.pop();//队首出列
        if(top.step==maxTime+1)//整个队列全超时
            return false;
        else if(maze[top.f][top.x][top.y]=='P')//找到公主
                return true;
​
        //朝四个方向尝试走
        for(int i=0;i<4;i++)
        {
            newF=top.f;
            newX=top.x+X[i];
            newY=top.y+Y[i];
                //printf("newF:%d newX:%d newY:%d\n",newF,newX,newY);
            if(judge(newF,newX,newY))
            {
                temp.f=newF;
                temp.x=newX;
                temp.y=newY;
                temp.step=top.step+1;//时间加1
                q.push(temp);//结点入队           //printf("temp.step:%d,temp.f:%d,temp.x:%d,temp.y:%d\n",temp.step,temp.f,temp.x,temp.y);
                inq[newF][newX][newY]=true;//另一层该入吗?
            }
        }
    }
    return false;//队列空了(超时)还没找到,就false
}
int main()
{
    //freopen("fopen.txt","r",stdin);
    int c;
    scanf("%d",&c);
    while(c--)
    {
        //读入数据
​
        scanf("%d%d%d",&n,&m,&maxTime);
        //第一层
        for(int i=0;i<n;i++)
        {
            getchar();//吃掉每次行尾那个换行符
            for(int j=0;j<m;j++)
            {
                maze[0][i][j]=getchar();
            }
        }
        getchar();//吃掉两层中间那个换行
        //第二层
        for(int i=0;i<n;i++)
        {
            getchar();//吃掉每次行尾那个换行符
            for(int j=0;j<m;j++)
            {
                maze[1][i][j]=getchar();
                                //cout<<maze[1][i][j];
            }
            //cout<<endl;
        }
        remake();//处理死路
        //初始化
        S.f=0;S.x=0;S.y=0;S.step=0;
​
        memset(inq,0,sizeof(inq));
        /
        if(BFS())
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}
​
​

胜利大逃亡

Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.  魔王住在一个城堡里,城堡是一个ABC的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1. 

Input

输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙.(如果对输入描述不清楚,可以参考Sample Input中的迷宫描述,它表示的就是上图中的迷宫)  特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.

Output

对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.

Sample Input

13 3 4 200 1 1 10 0 1 10 1 1 11 1 1 11 0 0 10 1 1 10 0 0 00 1 1 00 1 1 0

Sample Output

11

 

思路

BFS走三维迷宫,和A计划差不多,直接上代码了

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include<cmath>
#include<cstring>
#include<queue>
const int maxN=55;
using namespace std;
int newX,newY,newZ,A,B,C,maze[maxN][maxN][maxN];
int maxTime;
struct shit
{
    int x,y,z;
    int step;
}S,E,top,temp;
int inq[maxN][maxN][maxN];
void Move(int x)
{
    if(x==1) {newX=top.x+1;newY=top.y;newZ=top.z;}
    if(x==2) {newX=top.x-1;newY=top.y;newZ=top.z;}
    if(x==3) {newX=top.x;newY=top.y+1;newZ=top.z;}
    if(x==4) {newX=top.x;newY=top.y-1;newZ=top.z;}
    if(x==5) {newX=top.x;newY=top.y;newZ=top.z+1;}
    if(x==6) {newX=top.x;newY=top.y;newZ=top.z-1;}
​
}
bool judge(int x,int y,int z)
{
    if(x<0||x>=A||y<0||y>=B||z<0||z>=C) return false;
    if(maze[x][y][z]==1) return false;
    if(inq[x][y][z]==1) return false;
    return true;
}
int BFS()
{
    queue<shit> q;
    q.push(S);
    while(!q.empty())
    {
        top=q.front();
        q.pop();
        //printf("top.x:%d top.step:%d E.x:%d\n",top.x,top.step,E.x);
        if(top.step==maxTime+1)
            return -1;
         if(top.x==A-1&&top.y==B-1&&top.z==C-1)
            return top.step;
        for(int i=1;i<=6;i++)
        {
            Move(i);
            //printf("newX:%d\n",newX);
            if(judge(newX,newY,newZ))
            {
                temp.x=newX;
                temp.y=newY;
                temp.z=newZ;
                temp.step=top.step+1;
                //printf("newX:%d top.step:%d\n",newX,top.step);
                q.push(temp);
                inq[newX][newY][newZ]=1;
            }
        }
    }
    return -1;
}
int main()
{
    int K;
    scanf("%d",&K);
    while(K--)
    {
        scanf("%d %d %d %d",&A,&B,&C,&maxTime);
        for(int i=0;i<A;i++)
            for(int j=0;j<B;j++)
                for(int k=0;k<C;k++)
                    scanf("%d",&maze[i][j][k]);
        memset(inq,0,sizeof(inq));
        S.step=0;
        printf("%d\n",BFS());
    }
}

Asteroids!

You're in space.

You want to get home.

There are asteroids.

You don't want to hit them.

Input

Input to this problem will consist of a (non-empty) series of up to 100 data sets. Each data set will be formatted according to the following description, and there will be no blank lines separating data sets.  A single data set has 5 components:  Start line - A single line, "START N", where 1 <= N <= 10.  Slice list - A series of N slices. Each slice is an N x N matrix representing a horizontal slice through the asteroid field. Each position in the matrix will be one of two values:  'O' - (the letter "oh") Empty space  'X' - (upper-case) Asteroid present  Starting Position - A single line, "A B C", denoting the <A,B,C> coordinates of your craft's starting position. The coordinate values will be integers separated by individual spaces.  Target Position - A single line, "D E F", denoting the <D,E,F> coordinates of your target's position. The coordinate values will be integers separated by individual spaces.  End line - A single line, "END"  The origin of the coordinate system is <0,0,0>. Therefore, each component of each coordinate vector will be an integer between 0 and N-1, inclusive.  The first coordinate in a set indicates the column. Left column = 0.  The second coordinate in a set indicates the row. Top row = 0.  The third coordinate in a set indicates the slice. First slice = 0.  Both the Starting Position and the Target Position will be in empty space.

Output

For each data set, there will be exactly one output set, and there will be no blank lines separating output sets.  A single output set consists of a single line. If a route exists, the line will be in the format "X Y", where X is the same as N from the corresponding input data set and Y is the least number of moves necessary to get your ship from the starting position to the target position. If there is no route from the starting position to the target position, the line will be "NO ROUTE" instead.  A move can only be in one of the six basic directions: up, down, left, right, forward, back. Phrased more precisely, a move will either increment or decrement a single component of your current position vector by 1.

Sample Input

START 1O0 0 00 0 0ENDSTART 3XXXXXXXXXOOOOOOOOOXXXXXXXXX0 0 12 2 1ENDSTART 5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOXXXXXXXXXXXXXXXXXXXXXXXXXOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO0 0 04 4 4END

Sample Output

1 03 4NO ROUTE

 

思路

BBBBBBBBBBFFFFFFFFFFFFFFFFSSSSSSSSSSSSSSS!

注意

有六个方向可以走哦

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include<cmath>
#include<cstring>
#include<queue>
const int maxN=55;
using namespace std;
int newX,newY,newZ,N;
char maze[maxN][maxN][maxN];
int maxTime;
struct shit
{
    int x,y,z;
    int step;
}S,E,top,temp;
int inq[maxN][maxN][maxN];
void Move(int x)
{
    if(x==1) {newX=top.x+1;newY=top.y;newZ=top.z;}
    if(x==2) {newX=top.x-1;newY=top.y;newZ=top.z;}
    if(x==3) {newX=top.x;newY=top.y+1;newZ=top.z;}
    if(x==4) {newX=top.x;newY=top.y-1;newZ=top.z;}
    if(x==5) {newX=top.x;newY=top.y;newZ=top.z+1;}
    if(x==6) {newX=top.x;newY=top.y;newZ=top.z-1;}
​
}
bool judge(int x,int y,int z)
{
    if(x<0||x>=N||y<0||y>=N||z<0||z>=N) return false;
    if(maze[x][y][z]=='X') return false;
    if(inq[x][y][z]==1) return false;
    return true;
}
int BFS()
{
    queue<shit> q;
    q.push(S);
    while(!q.empty())
    {
        top=q.front();
        q.pop();
        //printf("top.x:%d top.step:%d E.x:%d\n",top.x,top.step,E.x);
        //if(top.step==maxTime+1)
            //return -1;
         if(top.x==E.x&&top.y==E.y&&top.z==E.z)
            return top.step;
        for(int i=1;i<=6;i++)
        {
            Move(i);
            //printf("newX:%d\n",newX);
            if(judge(newX,newY,newZ))
            {
                temp.x=newX;
                temp.y=newY;
                temp.z=newZ;
                temp.step=top.step+1;
                //printf("newX:%d top.step:%d\n",newX,top.step);
                q.push(temp);
                inq[newX][newY][newZ]=1;
            }
        }
    }
    return -1;
}
int main()
{
    //freopen("fopen.txt","r",stdin);
    char s[10];
    char c;
    while(~scanf("%s%d",s,&N))
    {
        getchar();
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<N;j++)
            {
                for(int k=0;k<N;k++)
                {
                    scanf("%c",&maze[j][k][i]);
                }
                getchar();
            }
            //getchar();
        }
        /*for(int i=0;i<N;i++)
        {
            for(int j=0;j<N;j++)
                {
                    for(int k=0;k<N;k++)
                    {
                        cout<<maze[j][k][i];
                    }
                    cout<<endl;
                }
        }*/
        //cout<<maze[0][0][0]<<"-"<<maze[0][0][1]<<"-"<<maze[0][0][2];
        scanf("%d %d %d",&S.x,&S.y,&S.z);
        scanf("%d %d %d",&E.x,&E.y,&E.z);
        scanf("%s",s);
        //printf("%d %d %d\n",S.x,S.y,S.z);
        //printf("%d %d %d\n",E.x,E.y,E.z);
        memset(inq,0,sizeof(inq));
        S.step=0;
        int ans=BFS();
        if(ans>=0)
        {
            printf("%d %d\n",N,ans);
        }
        else
            printf("NO ROUTE\n");
    }
    return 0;
}

A strange lift

There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button "UP" , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button "DOWN" , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can't go up high than N,and can't go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button "UP", and you'll go up to the 4 th floor,and if you press the button "DOWN", the lift can't do it, because it can't go down to the -2 th floor,as you know ,the -2 th floor isn't exist.  Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button "UP" or "DOWN"?

Input

The input consists of several test cases.,Each test case contains two lines.  The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,....kn.  A single 0 indicate the end of the input.

Output

For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can't reach floor B,printf "-1".

Sample Input

5 1 53 3 1 2 50

Sample Output

3

思路

一维空间的BFS

两种移动方式

void Move(int x)
{
    if(x==1) newX=top.x+a[top.x];
    if(x==2) newX=top.x-a[top.x];
}

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include<cmath>
#include<cstring>
#include<queue>
const int maxN=205;
using namespace std;
int newX,N,a[maxN];
struct shit
{
    int x;
    int step;
}S,E,top,temp;
int inq[maxN];
void Move(int x)
{
    if(x==1) newX=top.x+a[top.x];
    if(x==2) newX=top.x-a[top.x];
}
bool judge(int x)
{
    if(x<0||x>N) return false;
    if(inq[x]==1) return false;
    return true;
}
int BFS()
{
    queue<shit> q;
    q.push(S);
    while(!q.empty())
    {
        top=q.front();
        q.pop();
        //printf("top.x:%d top.step:%d E.x:%d\n",top.x,top.step,E.x);
        if(top.x==E.x)
            return top.step;
        for(int i=1;i<=2;i++)
        {
            Move(i);
            //printf("newX:%d\n",newX);
            if(judge(newX))
            {
                temp.x=newX;
                temp.step=top.step+1;
                //printf("newX:%d top.step:%d\n",newX,top.step);
                q.push(temp);
                inq[newX]=1;
            }
        }
    }
    return -1;
}
int main()
{
    while(scanf("%d",&N)==1&&N!=0)
    {
        scanf("%d %d",&S.x,&E.x);
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&a[i]);
        }
        memset(inq,0,sizeof(inq));
        S.step=0;
        printf("%d\n",BFS());
    }
}

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

 

思路

一维BFS

注意

广搜超过10000时及时推出,不然会爆

if(x<0||x>100000) return false;

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int newX;
struct shit
{
    int x;
    int step;
}S,E,top,temp;
const int maxN=100005;
int inq[maxN];
void Move(int x)
{
    if(x==1) newX=top.x + 1;
    if(x==2) newX=top.x - 1;
    if(x==3) newX=top.x * 2;
}
bool judge(int x)
{
    if(x<0||x>100000) return false;
    if(inq[x]==1) return false;
    return true;
}
int BFS()
{
    queue<shit> q;
    q.push(S);
    while(!q.empty())
    {
        top=q.front();
        q.pop();
        //printf("top.x:%d E.x:%d\n",top.x,E.x);
        if(top.x==E.x)
            return top.step;
        for(int i=1;i<=3;i++)
        {
            Move(i);
            //printf("newX:%d\n",newX);
            if(judge(newX))
            {
                temp.x=newX;
                temp.step=top.step+1;
                q.push(temp);
                inq[newX]=1;
            }
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d %d",&S.x,&E.x))
    {
        memset(inq,0,sizeof(inq));
        S.step=0;
        printf("%d\n",BFS());
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值