周六900C++班级2022-11-5 广搜

广度优先搜索

 

 

 第一步

 

 

 

 

 

 

7588: 农夫抓牛

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:

1、从X移动到X-1或X+1,每次移动花费一分钟

2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
    int x,y,step;
};
node q[100005];
int nex[3] = {-1,1,2};
int vis[100005]; //标记数组 
int n,k,f,ans; //f终点的标记 
void bfs()
{
    int head = 1,tail = 1;
    q[tail].x = n;
    q[tail].step = 0;
    tail++; //扩充队尾
    vis[n] = 1; //标记起点
    while(head<tail)
    {
        for(int i=0;i<3;i++)
        {
            int tx;
            if(i<2) tx = nex[i]+q[head].x; //方向数组+队首head的位置 
            else tx = nex[i]*q[head].x;
            if(tx>100000 || tx<0) continue;//越界判断
            if(vis[tx]==0) //vis数组里没标记过,那么就让tx加入队尾
            {
                vis[tx] = 1; //标记tx
                q[tail].x = tx;
                q[tail].step = q[head].step+1; 
                tail++; //扩充队列长度 
            } 
            if(tx==k){ //找到终点 
                f = 1;
                ans = q[tail-1].step;
                break;
            }
        }
        if(f)break;
        head++; //队首往后一位 
    } 
}
int main()
{
    cin>>n>>k; //输入起点终点 
    bfs(); //寻找最短路 
    cout<<ans; //输出最短路长 
     return 0;
}
View Code
复制代码

 

6878: 青蛙跳

一只青蛙沿着一条多个石头格子铺成的路去前方寻找虫子,某些格子有障碍物不能踩,但青蛙能够越过。已知青蛙一次最多能越过d个格子(如从第一个格子到第三个格子,越过了1个格子)。

路的一端是青蛙当前位置,另一端则是虫子所在位置(两个格子都没有障碍物),问青蛙最少需要跳几次才能到达虫子所在格子。

复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
    int x,y,step;
};
node q[100005];
int nex[3] = {-1,1,2};
int vis[100005]; //标记数组 
int n,k,f,ans; //f终点的标记 
string s;
void bfs()
{
    int head = 1,tail = 1;
    q[tail].x = 0;
    q[tail].step = 0;
    tail++; //扩充队尾
    vis[0] = 1; //标记起点
    while(head<tail)
    {
        for(int i=1;i<=k+1;i++)
        {
            int tx = q[head].x + i;
            if(tx>=n) continue;//越界判断
            if(vis[tx]==0 && s[tx]!='X') //vis数组里没标记过,那么就让tx加入队尾
            {
                vis[tx] = 1; //标记tx
                q[tail].x = tx;
                q[tail].step = q[head].step+1; 
                tail++; //扩充队列长度 
            } 
            if(tx==n-1){ //找到终点 
                f = 1;
                ans = q[tail-1].step;
                break;
            }
        }
        if(f)break;
        head++; //队首往后一位 
    }
}
int main()
{
    cin>>n>>k; 
    cin>>s;
    bfs(); //寻找最短路 
    cout<<ans; //输出最短路长 
     return 0;
}
View Code
复制代码

 

 

6314: 走迷宫

一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。

给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。

复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
    int step,x,y;
};
node q[1605]; //队列 
char a[50][50]; //地图
int vis[50][50]; //标记数组
int nex[4][2] = {{0,1},{1,0},{0,-1},{-1,0}}; //右下左上四个方向
int n,m,f,ans; //n行,m列,f终点标记 ,ans记录答案的步长
void bfs()
{
    int head = 1,tail = 1; //定义队首head,队尾tail
    q[tail].x = 1;
    q[tail].y = 1; 
    q[tail].step = 1; //14-16行 => 起点入队 
    tail++; //队尾扩充 
    vis[1][1] = 1; //给起点标记上
    while(head<tail)
    {
        for(int i=0;i<4;i++) //循环4个方向 
        {
            int tx = q[head].x + nex[i][0]; //下一步的坐标tx = 队首head.x + 第i个方向的x增量nex[i][0] 
            int ty = q[head].y + nex[i][1];
            if(tx<1 || tx>n || ty<1 || ty>m)continue; //越界判断 
            if(a[tx][ty]=='.' && vis[tx][ty] == 0) //判断tx,ty在地图a上是否可走 且 在标记数组vis上没标记过 
            {
                vis[tx][ty] = 1; //将下一步(tx,ty)在vis数组上标记 
                q[tail].x = tx;
                q[tail].y = ty;
                q[tail].step = q[head].step + 1; //队尾步长 = 队首步长 + 1  
                tail++; //扩充队尾 
            }
            if(tx==n && ty==m) //判断下一步坐标tx,ty是否已经是终点
            {
                f = 1; //标记终点已找到 
                ans = q[tail-1].step; //到终点的步长 = 队尾-1的步长 
                break;
            } 
        }
        if(f==1)break;
        head++; 
    } 
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j]; //输入第i行第j列的数据
    bfs();
    cout<<ans;     
    return 0;
}
View Code
复制代码

 

7587:仙岛求药

 少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。
下图 显示了一个迷阵的样例及李逍遥找到仙药的路线

复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
    int step,x,y;
};
node q[1605]; //队列 
char a[50][50]; //地图
int vis[50][50]; //标记数组
int nex[4][2] = {{0,1},{1,0},{0,-1},{-1,0}}; //右下左上四个方向
int n,m,f,ans; //n行,m列,f终点标记 ,ans记录答案的步长
int sx,sy,ex,ey;
void bfs()
{
    int head = 1,tail = 1; //定义队首head,队尾tail
    q[tail].x = sx;
    q[tail].y = sy; 
    q[tail].step = 0; //14-16行 => 起点入队 
    tail++; //队尾扩充 
    vis[sx][sy] = 1; //给起点标记上
    while(head<tail)
    {
        for(int i=0;i<4;i++) //循环4个方向 
        {
            int tx = q[head].x + nex[i][0]; //下一步的坐标tx = 队首head.x + 第i个方向的x增量nex[i][0] 
            int ty = q[head].y + nex[i][1];
            if(tx<1 || tx>n || ty<1 || ty>m)continue; //越界判断 
            if(a[tx][ty]!='#' && vis[tx][ty] == 0) //判断tx,ty在地图a上是否可走 且 在标记数组vis上没标记过 
            {
                vis[tx][ty] = 1; //将下一步(tx,ty)在vis数组上标记 
                q[tail].x = tx;
                q[tail].y = ty;
                q[tail].step = q[head].step + 1; //队尾步长 = 队首步长 + 1  
                tail++; //扩充队尾 
            }
            if(tx==ex && ty==ey) //判断下一步坐标tx,ty是否已经是终点
            {
                f = 1; //标记终点已找到 
                ans = q[tail-1].step; //到终点的步长 = 队尾-1的步长 
                break;
            } 
        }
        if(f==1)break;
        head++; 
    } 
}
int main()
{
    while(cin>>n>>m)
    {
        if(n==0&&m==0)break;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
            {
                cin>>a[i][j];
                if(a[i][j]=='@'){ //起点 
                    sx = i;sy = j;
                }
                if(a[i][j]=='*'){ //终点 
                    ex = i;ey = j;
                }
            }
        }
        memset(vis,0,sizeof(vis)); //将vis数组的全部数据初始化为0 
        ans = -1;  //
        f = 0;
        bfs();
        cout<<ans<<endl;         
    }
    
    return 0;
}
View Code
复制代码

5761: 最少步数

在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100×100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。

复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
    int step,x,y;
};
node q[10001]; //队列 
int vis[105][105]; //标记数组
int nex[12][2]={{1,2},{2,1},{1,-2},{-2,1},{-1,2},{2,-1},{-1,-2},{-2,-1},{2,2},{2,-2},{-2,2},{-2,-2}}; //右下左上四个方向
int n,m,f,ans; //n行,m列,f终点标记 ,ans记录答案的步长
int sx,sy,ex,ey;
void bfs()
{
    int head = 1,tail = 1; //定义队首head,队尾tail
    q[tail].x = sx;
    q[tail].y = sy; 
    q[tail].step = 0; //14-16行 => 起点入队 
    tail++; //队尾扩充 
    vis[sx][sy] = 1; //给起点标记上
    while(head<tail)
    {
        for(int i=0;i<12;i++) //循环4个方向 
        {
            int tx = q[head].x + nex[i][0]; //下一步的坐标tx = 队首head.x + 第i个方向的x增量nex[i][0] 
            int ty = q[head].y + nex[i][1];
            if(tx<1 || tx>100 || ty<1 || ty>100)continue; //越界判断 
            if(vis[tx][ty] == 0) //判断tx,ty在地图a上是否可走 且 在标记数组vis上没标记过 
            {
                vis[tx][ty] = 1; //将下一步(tx,ty)在vis数组上标记 
                q[tail].x = tx;
                q[tail].y = ty;
                q[tail].step = q[head].step + 1; //队尾步长 = 队首步长 + 1  
                tail++; //扩充队尾 
            }
            if(tx==ex && ty==ey) //判断下一步坐标tx,ty是否已经是终点
            {
                f = 1; //标记终点已找到 
                ans = q[tail-1].step; //到终点的步长 = 队尾-1的步长 
                break;
            } 
        }
        if(f==1)break;
        head++; 
    } 
}
int main()
{
    for(int u=1;u<=2;u++)
    {
        cin>>sx>>sy;
        memset(vis,0,sizeof(vis)); //初始化标记数组vis全部为0 
        f = 0; //终点标记 f = 0 
        ex = 1;ey = 1;
        bfs();
        cout<<ans<<endl;
    } 
    return 0;
}
View Code
复制代码

 

——————————————————————————————————————————————————

总结:

广搜相较于深搜来说更加的模板化其实应用范围也并不广,在蓝桥杯和CSP的考试中更多是考察类似于深搜的题目,但是广搜是在NOI大纲中的,作为搜寻最短路的方法,是要求大家掌握的,而且广搜是与图论最短路章节息息相关的内容,在未来考到的频次可能也会增加 所以想学好广搜需要注意的点是理清广搜这一过程中队列的思想,对于当前的队首head,能加入队尾tail的一定是跟队首head相连通的点才能加入队尾;记住循环是head<tail。细心的同学一定能看出来,BFS中最开始的初始化结束后tail会++;当确认下一点tx,ty可走时将tx,ty加入队尾tail后tail也会++,而队首head往后移是发生在head的方向循环结束后,代表这个队首head已经把所有方向都遍历完的情况下,才会让head++;

posted @   CRt0729  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示