[算法]BFS广度优先搜索(基础1)

前几天学习了广度优先搜索(Breadth-First Search),也就是BFS
啥是BFS呢,从名字不难看出来,这是一种搜索算法,并且以广度优先,很类似于现在的导航技术,能够找到从出发点到终点的最短走法。如果你你还是不懂,可以先看一下下面一道题目:

抓住那头牛问题
农夫丢失了他的一头牛,他决定追回他的牛。已知农夫和牛在一条直线上,初始位置分别为𝑥(𝑥>0)和𝑦,假定牛在原地不动。 农夫每分钟的行走方式为:

前进一步 𝑜𝑟 后退一步 𝑜𝑟 走到𝟐𝒙的位置

计算他最少需要几分钟追上他的牛。 (你能打印出行走的路线吗?)

让我们一起来分析一下这道题目:
如果你一开始直接思考整个过程,可能有点晕
所以我们弄个简单的,就画个一维的坐标图,点用来表示位置
假设一开始农夫在位置3,牛🐂在位置5
在这里插入图片描述
试着想一想我们要如何解决这种情况
如果要符合条件,也就是人的位置和牛🐂的位置相同
而人的位置改变只有三种方法

前进一步 ㅤ或者 ㅤ后退一步 ㅤ或者ㅤ 走到𝟐𝒙的位置

对于图中的农夫👨‍🌾来说,他从位置3走一步可以到达

位置4ㅤ位置2ㅤ位置6

那我们是不是只要跟随农夫👨‍🌾的路线走,到达这三个位置之后又可以有三种选择,再次到达新的位置
又因为要求最少需要多少步,那就是农夫👨‍🌾第一次到达牛🐂的位置的时候就是花费最少步数的情况

因此,我们可以画出一张图来帮助我们理解(画的一般,凑合着看吧)
在这里插入图片描述
农夫👨‍🌾一开始在位置3然后走一步可以到达位置2 位置4 位置6
到达位置2 位置4 位置6之后又可以到达新的位置

注意:这里我们寻找最少时间花费,也就是说不要走重复的路,比如说

位置3 ->位置2->位置3

Step1:用数组记录到过的位置

因此我们还需要加入一个vis数组来记录某个点是否已经走过
然后我们想,这个操作,一开始是位置3,然后分出到3个位置
我们从位置3到达位置位置4

那我们是因该先处理前面从位置3到达位置2和位置6的情况还是直接处理到达位置4后的情况

仔细想一下,我们前面想到的方法是一步一步走,每次只走一步,判断是否人的位置和牛🐂的位置相等,如果相等了,我们就可以得到一个计数变量,也就是我们要的最少需要几分钟

因此我们确定要先处理从位置3到达位置2和位置6的情况
不难想到我们可以用数据结构中的队列来模拟这个进程


Step2:用队列模拟这个过程

一开始把位置3加入队列中,每次操作取出队列元素,判断是否到达牛🐂的位置,如果是就返回计数变量,如果不是的话,就加入三个位置:4 2 6分别代表农夫👨‍🌾走一步能到达的你地方,不断重复这个动作直到农夫👨‍🌾到达牛🐂的位置

也就是下面这个动画
请添加图片描述
解释:图中黑色的圆是一开始的位置,蓝色的圆代表是第一步可以到达的位置,红色的圆是第二步可以到达的位置
注意一下,每次到达新的位置的时候要先判断这个位置之前是否已经走过!
最后输出的结果就是一个计数变量,记录第几步
最好能够自己动手写出这个过程


Step3:用数组记录并打印出行走路径

不难想到,我们可以用一个数组来记录行动路径 实际上是记录上一个位置所在的地方
根据刚刚的图我们可以画出下面的表格
在这里插入图片描述
数组下表表示一个位置,其数值表示上一个位置的数组下标,让我们找一找,数组下标为5其数值是4,接着找数组下标是4的数值是3,也就是到达另外一开始农夫的位置👨‍🌾,然后在反向遍历出来就可以输出行走路径

附上完整代码

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

#define Show_Queue 1			  /*两个宏定义用来表示是否输出队列以及路径数组*/
//#define Show_Wayarray 1

#define NOFOUND -1
#define MAXNUMBER 100

bool vis[MAXNUMBER] = {false};   /*用来记录是否曾经走过*/
int dis[MAXNUMBER] = {0};        /*用来记录从开始行动的这里的最短移动次数*/
int action[MAXNUMBER] = {0};     /*用来记录行动路径 实际上是记录前驱节点*/

int cnt = 0;                     /*用来数数 队列操作次数*/


/*用来判断数据是否有效*/
int judge(int x)
{
    if(x > 0 && x <= MAXNUMBER && vis[x] == false)
        return true;
    return 0;
}

int bfs(int x,int y)
{
    int next;
    queue<int>que;
    que.push(x);
    vis[x] = true;
    while(!que.empty())
    {
        cnt++;
        printf("%03d:",cnt);

#ifdef Show_Queue
        /*遍历整个队列*/
        int queue_size = que.size();
        for(int i = 0; i < queue_size; i++) 
        {   //queue_size 必须是固定值
            cout << que.front() << " ";
            que.push(que.front());
            que.pop();
        } 
        cout << endl;
#endif
        /*取出队首元素*/
        int u = que.front();
        que.pop();
        /*找到目标*/
        if(u == y)
            return dis[u];
        
        next = u + 1;
        /*判断下一步是否有效*/
        if( judge(next) )
        {
            que.push(next);
            vis[next] = true;
            dis[next] = dis[u] + 1;
            action[next] = u;
        }
        next = u - 1;
        if( judge(next) )
        {
            que.push(next);
            vis[next] = true;
            dis[next] = dis[u] + 1;
            action[next] = u;
        }
        next = 2 * u;
        if( judge(next) )
        {
            que.push(next);
            vis[next] = true;
            dis[next] = dis[u] + 1;
            action[next] = u;
        }

    }
    return NOFOUND;
}

/*用递归来打印出路径*/
void Find_Way(int start, int end)
{
    if(start == end)
        return ;
    Find_Way(start, action[end]);
    /*step是计算出来两个位置的差,来判断农夫的移动方式*/
    int step = end - action[end];
    if(step == 1)
        printf("从 %3d 向前走1步到%3d\n",action[end], end);
    else if(step == -1)
        printf("从 %3d 向后走1步到%3d\n",action[end], end);
    else
        printf("从 %3d 向前2倍步到%3d\n",action[end], end);
}

int main()
{
    int i;
    int start = 3;
    int end = 5;
    int ans;

    ans = bfs(start, end);
    printf("最快要走 %d 步到达!\n",ans);
    Find_Way(start, end);
#ifdef Show_Wayarray
    for(int temp = 0; temp < MAXNUMBER; ++temp)
    {
        printf("%d-%d\n",temp, action[temp]);
    }
#endif
    return 0;
}

跑一下程序:

001:3
002:4 2 6
003:2 6 5 8
004:6 5 8 1
005:5 8 1 7 12
最快要走 2 步到达!
从 3 向前走1步到 4
从 4 向前走1步到 5

得到答案


总结

总结一下bfs的做法:
1. 将起点star加入队列𝑞中,同时对该点进行更新
2. while 队列𝑞非空:
ㅤㅤ2.1 取出队首元素𝑢
ㅤㅤ2.2 判断𝑢是否为终点,若是终点跳出循环,并输出答案
ㅤㅤ2.3 遍历𝑢可到达的合法位置𝑣,将𝑣加入队列,并更新


作者是初学的小白,写这篇文章来来记录一下自己的学习过程,可能文章有一些错误,欢迎指正

附上基础2的链接:[算法]BFS广度优先搜索(基础2)

您的点赞和收藏是我前进的动力

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
BFS广度优先搜索算法(Breadth-First Search)是一种图的搜索算法,也是最简便的图搜索算法之一。它的目的是系统地展开并检查图中的所有节点,以找寻结果。这个算法不考虑结果的可能位置,而是彻底地搜索整张图,直到找到结果为止。广度优先搜索算法通常用于找出两个节点之间的最短路径。它可以帮助我们解决类似于寻找最短路径的问题。 BFS算法的基本思想是从起始节点开始,逐层地向外扩展,先访问离起始节点最近的节点,再逐渐向外层节点扩展,直到达到目标节点。它使用队列来存储待访问的节点,先进先出(FIFO)的特点保证了广度优先。通过不断地将节点加入队列并访问,直到队列为空,我们可以遍历整张图并找到最短路径。 BFS广度优先搜索算法的运行时间为O(V+E),其中V为顶点数,E为边数。它可以指出是否存在从起始节点到目标节点的路径,并且可以找到最短路径。当面临需要寻找最短路径的问题时,我们可以使用图来建立模型,并使用广度优先搜索算法解决问题。 参考资料: https://www.cnblogs.com/tianqizhi/p/9914539.html 文中引用的参考资料<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [代码 基于BFS广度优先搜索算法代码](https://download.csdn.net/download/s13166803785/85545057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [广度优先搜索算法BFS)详解](https://blog.csdn.net/lemonxiaoxiao/article/details/105730735)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

某新手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值