bfs入门题5道

8 篇文章 0 订阅
2 篇文章 0 订阅

Red and Black

原题:There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

'.' - a black tile
'#' - a red tile
'@' - a man on a black tile(appears exactly once in a data set)


Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).


Sample Input

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

Sample Output

45
59
6
13

解题思路:题意即求出以“@”为起点能够到达的每一个“.”

使用bfs算法遍历出每一个能够到达的“.”并计数输出即可

代码实现:

#include<stdio.h>
#include<queue>
using namespace std;
char mp[30][30];//地图
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};//方向向量
int m,n;
struct node
{
    int x;
    int y;
};//点结构体
int bfs(int sx,int sy)
{
    int a[30][30]={0};//对走过的点标记
    int cou=1;//计数器
    queue<node>q;
    node now,next;
    now.x=sx;
    now.y=sy;
    q.push(now);//放入起点
    while(q.size())
    {
        now=q.front();//拿出队列首位的点
        for(int i=0; i<4; i++)
        {
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            if(mp[next.x][next.y]=='.'&&(next.x>=0&&next.x<n&&next.y>=0&&next.y<m)&&!a[next.x][next.y])//判断是否出界或者走过
            {
                q.push(next);
                a[next.x][next.y]=1;
                cou++;
            }
        }
        q.pop();
    }
    return cou;
}
int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        int x,y;
        if(n==0&&m==0)break;
        for(int i=0; i<n; i++)
        {
            scanf("%s",mp[i]);//读图
        }
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
            {
                if(mp[i][j]=='@')
                {
                    x=i;
                    y=j;
                    break;//找起点
                }
            }
        printf("%d\n",bfs(x,y));
    }
    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 pointN (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 orX + 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.
解题思路:一维上的bfs搜索,搜索的同时记录时间即可
代码实现:
#include<stdio.h>
#include<queue>
using namespace std;
int bfs(int sx,int nx)
{
    queue<int>q;
    int dir[2]={-1,1};//一维方向向量
    int use[110000]={0};//路径标记
    int now,next;
    now=sx;
    q.push(now);//压入起点
    while(q.size())
    {
        now=q.front();
        for(int i=0;i<3;i++)
        {
            if(i==2)next=now*2;
            else next=now+dir[i];
            if(next>=0&&next<=100000&&!use[next])//判断是否越界或者搜过
            {
                use[next]=use[now]+1;
                if(next==nx)break;//找到终点
                q.push(next);
            }
        }
         if(next==nx)break;//找到终点
         else q.pop();
    }
    return use[next];
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    if(n==k)printf("0");//若起点和终点重合,直接输出0,否则会输出2
    else printf("%d",bfs(n,k));
    return 0;
}


A strange lift  

原题: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 willGo 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 5
3 3 1 2 5
0
Sample Output
3

解题思路:一维bfs搜索,记录时间即可,注意若搜不到,队列的最终状态

代码:

#include<stdio.h>
#include<queue>
using namespace std;
int n;
int mp[300];
int dir[2]={1,-1};//方向向量,上或下
struct node
{
    int x;
    int step;
};
int bfs(int sx,int nx)
{
    queue<node>q;
    int use[300]={0};
    node now,next;
    now.step=0;
    now.x=sx;
    q.push(now);
    while(q.size())
    {
        now=q.front();
        for(int i=0;i<2;i++)
        {
            next.x=now.x+dir[i]*mp[now.x];//转移
            if(next.x>=1&&next.x<=n&&!use[next.x])//判断
            {
                next.step=now.step+1;
                if(next.x==nx)break;
                use[next.x]=1;
                q.push(next);
            }
        }
        if(next.x==nx)break;
        q.pop();
    }
    if(q.size())return next.step;//如果找到,队列里必定剩余元素
    else return -1;//找不到则,队列为空
}
int main()
{
    int a,b;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        scanf("%d%d",&a,&b);
        for(int i=1;i<=n;i++)
            scanf("%d",&mp[i]);
        if(a==b)printf("0\n");//判断起点终点是否重合
        else printf("%d\n",bfs(a,b));
    }
    return 0;
}

Knight Moves

原题:Knight Moves                    
A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.

Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
Input
The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.
Output
For each test case, print one line saying "To get from xx to yy takes n knight moves.".
Sample Input
e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6
Sample Output
To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.
解题思路:简单的bfs搜索,输入的坐标转化为二维直角坐标,搜素即可
国际象棋的走法同中国象棋的马的走法相同
代码实现:
#include<stdio.h>
#include<queue>
using namespace std;
struct node
{
    int x;
    int y;
    int step;
};
int dir[8][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};//方向向量
int bfs(node now,node endd)
{
    queue<node>q;
    node next;
    int use[8][8]={0};
    now.step=0;
    q.push(now);
    while(q.size())//搜索
    {
        now=q.front();
        for(int i=0;i<8;i++)
        {
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            if(next.x>=0&&next.x<8&&next.y>=0&&next.y<8&&!use[next.x][next.y])
            {
                next.step=now.step+1;
                if(next.x==endd.x&&next.y==endd.y)break;
                use[next.x][next.y]=1;
                q.push(next);
            }
        }
        if(next.x==endd.x&&next.y==endd.y)break;
        q.pop();
    }
    return next.step;
}
int main()
{
   char sn[2][3]={0};
   node a[2];
   while(scanf("%s%s",sn[0],sn[1])!=EOF)
   {
       for(int i=0;i<2;i++)
       {
           a[i].x=sn[i][0]-97;
           a[i].y=sn[i][1]-49;
       }//坐标转换
       sn[0][2]='\0';
       sn[1][2]='\0';
       if(a[0].x==a[1].x&&a[0].y==a[1].y)printf("To get from %s to %s takes 0 knight moves.\n",sn[0],sn[1]);//起点终点重合的判断
       else printf("To get from %s to %s takes %d knight moves.\n",sn[0],sn[1],bfs(a[0],a[1]));
   }
   return 0;
}

A计划

原题:A计划                    

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

Input
输入的第一行C表示共有C个测试数据,每个测试数据的前一行有三个整数N,M,T。 N,M迷宫的大小N*M(1 <= N,M <=10)。T如上所意。接下去的前N*M表示迷宫的第一层的布置情况,后N*M表示迷宫第二层的布置情况。
Output
如果骑士们能够在T时刻能找到公主就输出“YES”,否则输出“NO”。
Sample Input
1
5 5 14
S*#*.
.#...
.....
****.
...#.

..*.P
#.*..
***..
...*.
*.#..
Sample Output
YES

解题思路:较复杂的迷宫问题,可以用三维数组存地图,然后使用bfs进行搜索,寻点时可以先确定下一个点的X,Y再判断是否是传送门。若是,换层,不是则与原层保持一致

若在换层之后的点上还是传送,此时的效果应与撞墙相同

代码实现:

#include<stdio.h>
#include<queue>
using namespace std;
struct node
{
    int z;
    int x;
    int y;
    int u;
};
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int bfs(char mp[2][11][11],int t,int n,int m)
{
    queue<node>q;
    node now,next;
    int use[2][11][11]={0};
    use[0][0][0]=1;
    now.z=0;
    now.y=0;
    now.x=0;
    now.u=0;
    q.push(now);
    while(q.size())
    {
        now=q.front();
        for(int i=0;i<4;i++)
        {
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            if(mp[now.z][next.y][next.x]!='#')next.z=now.z;//楼层转换判断
            else next.z=!now.z;
            if(next.x>=0&&next.x<m&&next.y>=0&&next.y<n&&!use[next.z][next.y][next.x]&&mp[next.z][next.y][next.x]!='*'&&mp[next.z][next.y][next.x]!='#')//判断是否越界,撞墙(包括换层之后遇到传送门的情况)
            {
                next.u=now.u+1;
                if(mp[next.z][next.y][next.x]=='P')break;
                use[next.z][next.y][next.x]=1;
                q.push(next);
            }
        }
        if(mp[next.z][next.y][next.x]=='P')break;
        q.pop();
    }
    if(q.size()&&next.u<=t)return 1;//若q.size()=0,则未搜寻到
    else return 0;
}
int main()
{
    int c,t,n,m;
    scanf("%d",&c);
    for(int s=0;s<c;s++)
    {
        scanf("%d%d%d",&n,&m,&t);
        char mp[2][11][11];
        for(int i=0; i<2; i++)
        {
            for(int j=0;j<n;j++)
                scanf("%s",mp[i][j]);//读入地图
        }
        if(bfs(mp,t,n,m))printf("YES\n");
        else printf("NO\n");
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值