广度优先搜索(模板使用)

广度优先搜索(模板使用)

模板出处

  • 关于模板出处,来自这里

  • 本文仅通过例题对模板的使用进行说明。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量

struct State{ // BFS 队列中的状态数据结构
    int x,y; // 坐标位置
    int Step_Counter; // 搜索步数统计器
};

State a[maxn];

bool CheckState(State s){ // 约束条件检验
    if(!vst[s.x][s.y] && ...) // 满足条件
    return 1;
    else // 约束条件冲突
    return 0;
}

void bfs(State st){
    queue <State> q; // BFS 队列
    State now,next; // 定义2 个状态,当前和下一个
    st.Step_Counter=0; // 计数器清零
    q.push(st); // 入队
    vst[st.x][st.y]=1; // 访问标记
    while(!q.empty()){
        now=q.front(); // 取队首元素进行扩展
        if(now==G){ //出现目标态,此时为Step_Counter 的最小值,可以退出即可
            ...... // 做相关处理
            return;
        }
        for(int i=0;i<4;i++){ // 如果状态满足约束条件则入队
            next.x=now.x+dir[i][0]; // 按照规则生成下一个状态
            next.y=now.y+dir[i][1];
            next.Step_Counter=now.Step_Counter+1; // 计数器加1
            if(CheckState(next)){
                q.push(next);
                vst[next.x][next.y]=1; //访问标记
            }
        }
        q.pop(); // 队首元素出队
    }
    return;
}

int main()
{
    ......
    return 0;
}

例题1:油田

题目说明:

某石油勘探公司正在按疾患勘探地下油田资源,在一片长方形地域中工作。他们首先将该地域划分为许多小正方形区域,然后使用勘探设备分别探测在每一小正方形区域内是否有油。含有油的区域被称为油田。如果两个油田相邻(在水平、垂直或对角线相邻),则它们是相同油藏的一部分。油藏可能非常大并可能包含许多油田(油田的个数不超过100)。你的工作是确定在这个长方形地域中包含多少不同的油藏。

输入:输入文件包含一个或多个长方形地域。每个地域的第1行都有两个正整数 m m m n ( 1 ≤ m , n ≤ 100 ) n(1 \leq m,n \leq 100) n(1m,n100),表示地域的行数和列数。如果 m = 0 m = 0 m=0,则表示输入结束;否则此后有 m m m行,每行都有 n n n个字符。每个字符都对应一个正方形区域,字符*表示没有油,字符@表示有油。

输出:对于每个长方形地域,都单行输出油藏的个数。

算法设计

  • 使用广度优先搜索模板进行求解

  • 约束条件为坐标出界限制,对应点是否为油田,标记数组。共3个

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10;
int m,n; //行数,列数
int ans = 0; //油田数量
bool vst[maxn][maxn]; // 访问标记
char str[maxn][maxn]; //油田矩阵
int dir[8][2]={-1,-1,-1,0,-1,1,
               0,-1,0,1,1,-1,
               1,0,1,1}; // 方向向量
struct state{ // BFS 队列中的状态数据结构
    int x,y; // 坐标位置
    int step; // 搜索步数统计器
};
bool check(state s); //约束条件检验
void bfs(int i,int j); //广度优先搜索
int main(){
    memset(vst,false,sizeof(vst)); //标记数组初始化
    cin >> m >> n;
    for (int i = 0; i < m; ++i) { //存储油田
        for (int j = 0; j < n; ++j) {
            cin >> str[i][j];
        }
    }
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            if(str[i][j] == '@' && !vst[i][j]){
                bfs(i,j);
                ans++;
            }
        }
    }
    cout << ans << endl;
    return 0;
}
bool check(state s){  // 约束条件检验
    if(s.x >= 0 && s.x < m && s.y >= 0 && s.y < n && str[s.x][s.y] == '@' && !vst[s.x][s.y]){
        return true;
    }
    return false;
}

void bfs(int i,int j){
    queue<state> q; //BFS队列
    state now,next; //定义2个状态,当前和下一个
    next.x = i; //将油田入队
    next.y = j;
    next.step = 0;
    q.push(next);
    vst[next.x][next.y] = true;
    while(!q.empty()){
        now = q.front(); //取队首元素扩展
        for (int k = 0; k < 8; ++k) { //8个方向扩展
            next.x = now.x+dir[k][0]; //按照规则生成下一个状态
            next.y = now.y+dir[k][1];
            next.step = now.step+1;
            if(check(next)){ //判断是否满足约束条件
                q.push(next);
                vst[next.x][next.y] = true; //标记访问
            }
        }
        q.pop(); //队首元素出队
    }
}

输入

5 5
****@
*@@*@
*@**@
@@@*@
@@**@

输出

2

例题2:抓住那头牛

题目描述

约翰希望立即抓住逃亡的牛。当前约翰在节点 N N N,牛在节点 K ( 0 ≤ N , K ≤ 100000 ) K(0 \leq N,K \leq 100000) K(0N,K100000)时,他们在同一条线上。约翰有两种交通方式:步行和乘车。如果牛不知道有人在追赶自己,原地不动,那么约翰需要多长时间才能抓住牛?

  • 步行:约翰可以在一分钟内从任意节点 X X X移动到节点 X − 1 X-1 X1 X + 1 X+1 X+1
  • 乘车:约翰可以在一分钟内从任意节点X移动到节点 2 × X 2 \times X 2×X

输入:两个整数 N N N K K K

输出:单行输出约翰抓住牛所需的最短时间(以分钟为单位)。

算法设计

  • 此题是在一维空间下的,与二维空间略有不同。

  • 移动方式有改变,这一点在更新状态方面可以看出。

  • 约束条件为,一维坐标大于0且小于50(这里的50主要是为了防止无意义的搜索,因为一旦超过50,即使往回走也一定不是最优解,所以要根据牛所处的位置而定),标记数组,共3个

#include <bits/stdc++.h>
using namespace std;
const int maxn = 20;
int n,k;//约翰的距离、牛的距离
bool vst[maxn]; // 访问标记
struct state{ // BFS 队列中的状态数据结构
    int x; // 坐标位置
    int time; // 搜索用时间
};
bool check(state s); //约束条件函数
void bfs(int temp); //广度优先搜索
int main(){
    cin >> n >> k;
    memset(vst,false,sizeof(vst)); //标记数组初始化
    bfs(n); //起点为5,从5开始进行广度优先搜索
}
bool check(state s){  // 约束条件检验
    if(s.x >= 0 && s.x <= 50 && !vst[s.x]){
        return true;
    }
    return false;
}

void bfs(int temp){
    queue<state> q;
    state now,next; // 定义2 个状态,当前和下一个
    next.x = temp;
    next.time = 0;
    q.push(next);
    vst[temp] = true; //标记访问
    while(!q.empty()){
        now = q.front();
        if(now.x == k){ //出现目标态,输出时间,退出即可
            cout << now.time << endl;
            return;
        }
        next.x = now.x+1; //按照规则生成下一个状态
        if(check(next)){
            next.time = now.time + 1; //更新下一个状态的时间
            vst[next.x] = true; //访问标记
            q.push(next); //入队
        }
        next.x = now.x-1; //按照规则生成下一个状态
        if(check(next)){
            next.time = now.time + 1; //更新下一个状态的时间
            vst[next.x] = true; //访问标记
            q.push(next); //入队
        }
        next.x = now.x*2; //按照规则生成下一个状态
        if(check(next)){
            next.time = now.time + 1; //更新下一个状态的时间
            vst[next.x] = true; //访问标记
            q.push(next); //入队
        }
        q.pop(); //出队
    }
}

输入

5 17

输出

4

试题C:扩散

问题描述

小蓝在一张无限大的特殊画布上作画。
这张画布可以看成一个方格图,每个格子可以用一个二维的整数坐标表示。
小蓝在画布上首先点了一下几个点(0,0)、(2020,11)、(11,14)、(2000,2000)。只有这几个格子上有黑色,其他位置都是白色的。
每过一分钟,黑色就会扩散一点。具体的,如果一个格子里面全是黑色,它就会扩散到上、下、左、右四个相邻的格子中,使得这四个格子也变成黑色(如果原来就是黑色,则还是黑色)。
请问,经过2020分钟后,画布上有多少个格子是黑色的。

算法设计

  • 暴力求解很容易爆内存,所以选用BFS(广度优先搜索)算法是一种方法。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10000;
int ans = 4; //已经存在4个黑点
bool vst[maxn][maxn]; //访问标记
int dir[4][2] = {0,1,0,-1,1,0,-1,0}; //方向向量
struct State{
    int x,y; //坐标位置
    int step; //搜索步数统计器
};
bool check(State s); //约束条件检验函数
void bfs(); //广度优先搜索
int main(){
    memset(vst,false,sizeof(vst)); //标记数组初始化
    bfs();
    cout << ans << endl;
    return 0;
}
bool check(State s){
    if(!vst[s.x][s.y] && s.step<=2020){ //坐标未被访问,且步数(即时间)小于等于2020
        return true;
    }
    return false;
}

void bfs(){
    queue<State> q; //BFS队列
    State now,next; //当前状态,下一个状态
    vst[3000][3000]=vst[5020][3011]=vst[3011][3014]=vst[5000][5000]=true;
    next.x=3000,next.y=3000,next.step=0;
    q.push(next);
    next.x=5020,next.y=3011,next.step=0;
    q.push(next);
    next.x=3011,next.y=3014,next.step=0;
    q.push(next);
    next.x=5000,next.y=5000,next.step=0;
    q.push(next);
    while(!q.empty()){
        now = q.front();
        for (int i = 0; i < 4; ++i) {
            next.x = now.x+dir[i][0];
            next.y = now.y+dir[i][1];
            next.step = now.step+1;
            if(check(next)){
                q.push(next);
                vst[next.x][next.y] = true; //标记访问
                ans++;
            }
        }
        q.pop(); //出队
    }
}

输出:

20312088
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
广度优先搜索(BFS)是一种用于或树的遍历算法,它从起始节点开始逐层地向外扩展,直到找到目标节点或遍历完所有节点。BFS通常使用队列来实现。 下面是BFS的基本思路及模板: 1. 创建一个队列,并将起始节点放入队列中。 2. 创建一个集合(或哈希表),用于记录已经访问过的节点。 3. 循环执行以下步骤,直到队列为空: - 从队列中取出一个节点作为当前节点。 - 如果当前节点是目标节点,算法结束。 - 否则,将当前节点标记为已访问,并将其所有未访问过的相邻节点加入队列。 4. 若队列为空且未找到目标节点,则目标节点不可达。 下面是一个示例的BFS模板使用Python语言): ```python from collections import deque def bfs(graph, start, target): queue = deque() queue.append(start) visited = set() visited.add(start) while queue: current_node = queue.popleft() # 判断是否找到目标节点 if current_node == target: return True # 将当前节点的未访问相邻节点加入队列 for neighbor in graph[current_node]: if neighbor not in visited: queue.append(neighbor) visited.add(neighbor) return False ``` 其中,`graph`是一个字典,表示的邻接关系;`start`是起始节点;`target`是目标节点。 你可以根据具体的问题定义自己的,并调用`bfs`函数进行搜索。注意,上述模板假设中的节点用唯一的标识符表示,如果节点具有其他属性,可以根据实际情况进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

羽星_s

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

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

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

打赏作者

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

抵扣说明:

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

余额充值