当前位置: 首页 > article >正文

C++————广度优先搜索(基础)

 广度优先搜索(Breadth-First Search,简称 BFS)是一种用于遍历或搜索树或图的算法。

原理

BFS 从给定的起始节点开始,逐层地访问图或树中的节点。具体来说,它先访问起始节点的所有邻接节点(即距离起始节点为 1 的节点),然后再依次访问这些邻接节点的邻接节点(距离起始节点为 2 的节点),以此类推,直到遍历完所有可达节点或找到目标节点。

广度优先搜索是一种队列式搜索,特点就是具有迭代和遍历的属性,本文以二维数组为例。

广度优先搜索在基本情况下(即无边界)就像洪水蔓延一样,接下来以Minecraft(我的世界)演示。

假设绿宝石块的地方是搜索原点,每种不同的方块代表一代。

搜索的基本单位是搜索点和与其距离1的相邻格,也就是绿宝石和金块组成的单位(绿宝石块和他的上下左右)

我的世界模拟广度优先搜索

算法步骤

  1. 初始化
    • 创建一个队列(Queue),用于存储待访问的节点。
    • 创建一个访问标记数组(Visited Array),用于记录每个节点是否已经被访问过。
    • 将起始节点加入队列,并标记为已访问。
  2. 循环处理队列
    • 当队列不为空时,取出队列的头部节点。
    • 处理该节点(例如,打印节点信息、检查是否为目标节点等)。
    • 遍历该节点的所有邻接节点,如果邻接节点未被访问过,则将其加入队列,并标记为已访问。
  3. 结束条件
    • 当队列为空时,说明所有可达节点都已被访问,算法结束。

 技巧:

1.记忆化:

 每次搜索的都是当前的上下左右,那么如果仅是单纯的重复搜索,那么一个节点可能会被访问无数次,所有可以通过改变数组元素,或者建立访问数组。

2.建立方向数组:

分别代表上下左右xx=x+X[i],yy=y+Y[i]。

int X[4]={-1,1,0,0},Y[4]={0,0,-1,1};
3.使用<queue>和结构体

建立一个放置坐标队列,先进先出的队列能保证按照层次搜索。

struct node {
    int x;
    int y;
};
queue<node> q;
4.合法性判断 :

只有不越界并且符合的坐标才能入队。

代码实现: 

 自创一道模版题,填坑游戏,0代表平坦,1代表是坑,相连的1属于一个坑,问一共要填多少个坑。

遍历整个数组,检测到坑,就把这一整个坑填起来,记录坑的总数。

#include<iostream>
#include<queue>
using namespace std;
struct node {
    int x;
    int y;
};
queue<node> q;
int X[4]={-1,1,0,0},Y[4]={0,0,-1,1};
int a[4][8]={
    {0,0,1,1,0,0,0,0},
    {0,0,0,1,1,1,0,0},
    {1,1,0,1,1,0,1,1},
    {0,0,0,0,1,0,1,1}
};
int main() {
    int ans=0;
    for (int j = 0; j < 4; ++j) {
        for (int k = 0; k < 8; ++k) {
            if(a[j][k]==1) {q.push({j,k});++ans;}
            while(!q.empty()) {
                int x=q.front().x;
                int y=q.front().y;
                q.pop();
                for(int i=0;i<4;++i) {
                    int xx=x+X[i];
                    int yy=y+Y[i];
                    if(xx>=0 && xx<4 && yy>=0 && yy<8&&a[xx][yy]==1) {
                        q.push({xx,yy});
                        a[xx][yy]=0;
                    }
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

例题进阶:

1.洛谷P1162填涂颜色

题目大意:1圈内的0改成2.

方法:改圈内的会很麻烦,所有我们改圈外的,初始v数组,再建立一个ans数字存最终答案

这个圈最大的情况就是边界,我们把边界上是0的点都入队,这样就能找到圈外。

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct node {
    int x,y;
};
queue<node> q;
int n,a,b,X[4]={-1,+1,0,0},Y[4]={0,0,-1,1};//上下左右
int main() {
    cin>>n;
    vector<vector<int>> v(n,vector<int>(n,0));
    vector<vector<int>> ans(n,vector<int>(n,0));
    for(int i=0,check=1;i<n;i++) {
        for(int j=0;j<n;j++) {
            cin>>v[i][j];
            ans[i][j]=v[i][j];
        }
    }
    for(int i=0;i<n;i++) {
        if(v[i][0]==0) {q.push({i,0});v[i][0]=1;}
        if(v[i][n-1]==0) {q.push({i,n-1});v[i][n-1]=1;}
        if(v[0][i]==0) {q.push({0,i});v[0][i]=1;}
        if(v[n-1][i]==0) {q.push({n-1,i});v[n-1][i]=1;}
    }
    while(!q.empty()) {
        int x=q.front().x,y=q.front().y;
        q.pop();
        for(int i=0;i<4;i++) {
            int xx=x+X[i],yy=y+Y[i];
            if(xx>=0&&xx<n&&yy>=0&&yy<n&&v[xx][yy]==0) {
                q.push({xx,yy});
                v[xx][yy]=1;
            }
        }
    }
    for(int i=0;i<n;i++) {
        for(int j=0;j<n;j++) {
            if(v[i][j]==0) {ans[i][j]=2;}
            cout<<ans[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}
2.洛谷P1443马的遍历

题目大意:象棋中马的规则,判断几部能到达某个格子

由于我们的广度优先搜索bfs是逐层的,处理这种几步的题很方便,到达不了的地方是-1,干脆从初始化就是-1,然后到达的地方进行记忆化,每层+1。

(X[],Y[]是很灵活的)

#include<iostream>
#include<vector>
#include<queue>
using namespace std;

struct node {
    int x, y;
};

queue<node> q;
int n, m, x, y, X[8] = {-1, 1, -1, 1, -2, 2, -2, 2}, Y[8] = {2, 2, -2, -2, 1, 1, -1, -1};

int main() {
    cin >> n >> m >> x >> y;
    vector<vector<int> > v(n + 1, vector<int>(m + 1, -1));
    v[x][y] = 0;
    q.push({x, y});
    while (!q.empty()) {
        x = q.front().x;
        y = q.front().y;
        q.pop();
        for (int i = 0; i < 8; i++) {
            int xx = x + X[i];
            int yy = y + Y[i];
            if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && v[xx][yy] == -1) {
                q.push({xx, yy});
                v[xx][yy] = v[x][y] + 1;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cout << v[i][j] << " ";
        }
        cout << endl;
    }
    return 0
}


http://www.kler.cn/a/542618.html

相关文章:

  • [特殊字符] 基于 FastAPI 和 React 构建车牌号识别网站
  • 7.推荐系统的评价与优化
  • 如何在Kickstart自动化安装完成后ISO内拷贝文件到新系统或者执行命令
  • 任务调度算法在操作系统中的应用
  • Linux磁盘空间使用率100%(解决删除文件后还是显示100%)
  • 解释和对比“application/octet-stream“与“application/x-protobuf“
  • DeepSeek入门到精通!(清华大学104页ppt下载)
  • Tauri Windows入门开发避坑指南
  • Git 钩子的应用与自动化流程
  • 制药行业 BI 可视化数据分析方案
  • Qt QOpenGLWidget详解
  • docker 安装--离线
  • SaaS+AI应用架构:业务场景、智能体、大模型、知识库、传统工具系统
  • 停止回答 definecomponent is not defined
  • 基于脚本的modelsim自动化仿真笔记
  • 算法随笔_44: 最大矩形
  • AI时代下的安全堡垒:零信任模式如何守护你的AI系统
  • elementUI表单校验失败自动聚焦到失败input/select等输入框
  • 云计算如何推动数字化转型?
  • HTTP请求响应分析:HTTP/1.1→HTTP/2
  • 分布式通信处理层中kafka和Redis的作用
  • 《从入门到精通:蓝桥杯编程大赛知识点全攻略》(十一)-回文日期、移动距离、日期问题
  • VPN服务器是怎么把数据转发到外网的?
  • 二、k8s项目的生命周期
  • PostgreSQL 18新特性之DML语句RETURNING增强
  • java微服务常用技术