BFS(宽搜算法)入门

BFS算法经常需要用到队列辅助,如二叉树的层次遍历。
下面简单回顾一下队列的使用:

#include <queue>
#include <cstdio>
#include <iostream>

using namespace std;

int main()
{
    queue<int> q;
    q.push(1);
    q.push(3);
    q.push(5);
    q.pop();
    
    int a = q.front();
    int b = q.back();
    int c = q.size();
    int d = q.empty();
    cout << a << " " << b << " " << c << " " << d << " " << endl;
    //cout : 3 5 2 0 
    return 0;
}

然后简单回顾一下图的层次遍历算法(宽度优先搜索),对于这里不了解的同学请在数据结构中学习相关内容。对于下图,其层次遍历序列为:1 2 3 4 5 6 7(从上往下,从左往右)
在这里插入图片描述

层次遍历算法思想:维护一个队列,用于存放节点的信息。当访问到一个节点的时候,先访问该节点,然后将该节点的左右儿子分别入对列。

层次遍历算法模板:
在这里插入图片描述

下面以一个例子加深BFS算法的理解:

原题链接

有一个奇怪的电梯,他可以停在任何一层,并且在每个楼层有一个Ki(0<= Ki<=
N)。电梯只有两个按钮:上、下。当你在第i层,如果你按下“UP”按钮,你将上升Ki层,也就是说,你将会到达第i+Ki层,如果你按下“DOWN”按钮,你会下降Ki层,即您将前往第i-Ki层。当然,电梯不能高于N,也不能低于1。

例如,有5层的建筑物,并且k1=3,k2=3,k3=1,k4=2,k5=5。从1楼开始,你可以按下“UP”按钮,你会到4楼,但如果你按下“DOWN”按钮,电梯不做处理,因为它不能下到-2楼。

问:当你在A楼而想去B楼时,至少须按下“UP”或“DOWN”按钮多少次?其中,1<= N,A,B <= 200

分析:

  • 假如当前某人处在第5层且第5层的数字为2,那么如果按下“UP”按钮,他可以去到第7层,按下“DOWN”按钮他可以去到第3层。
  • 同理,如果第7层的数字为1,在第7层按下“UP”按钮,他可以去到第8层,按下“DOWN”按钮他可以去到第6层。
  • 如果第3层的数字为2,他可以去第1层和第5层。
  • 最终可以画出如下所示的状态转移图
  • 从下图可以得到,从第5层到第3/7层只需要1步,从第5层到第1/6/8层需要2步… …
    在这里插入图片描述
    下面是本题的AC代码及详细注释
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>

using namespace std;

int n,Start,End; //n表示楼层高度
int k[205]; //存储每层的数
int vis[205]; //标记数组,记录当前楼层是否来过,初始为0

struct pos//结构体
{
    int level;//当前在哪一层
    int step;//当前已经行走的步数
};

void bfs()//宽搜,搜索到目标level时输出其对应的step
{
    memset(vis,0,sizeof vis);//每次都需要重置状态数组
    
    pos cur,nex;//定义两个结构体分别表示当前和将要搜索的状态
    
    cur.level = Start;
    cur.step = 0;//当前在第start层且搜索0次
    
    queue<pos> qu;//定义一个结构体类型的队列
    qu.push(cur);//将当前状态入队,此时队列非空
    vis[Start] = 1;//将当前楼层标记为被访问过
    
    while (!qu.empty())//队列非空
    {
        cur = qu.front();//获得队首元素
        qu.pop();//队首元素出队
        if (cur.level == End)//搜索到目标level
        {
            cout << cur.step << endl;
            return;
        }
        
        //按下"UP"
        nex.level = cur.level + k[cur.level];
        nex.step = cur.step + 1;
        if (nex.level <= n)//下一个楼层不超过楼层总数且未被访问过
        {
            if (vis[nex.level] == 0)
            {
                vis[nex.level] = 1;//将下一个楼层标记为已经被访问过
                qu.push(nex);
            }
        }
        
        //按下"DOWN"
        nex.level = cur.level - k[cur.level];
        nex.step = cur.step + 1;
        if (nex.level >= 1)//下一个楼层不小于1且未被访问过
        {
            if (vis[nex.level] == 0)
            {
                vis[nex.level] = 1;
                qu.push(nex);
            }
        }
    }
    
    printf("-1\n");//循环完毕仍没搜索到结果
    return;
}

int main()
{
    while (cin >> n && n)
    {
        cin >> Start >> End;
        
        for (int i = 1 ;i <= n;i++) cin >> k[i];
        
        bfs();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值