news 2026/6/15 17:48:29

【算法题】多源BFS

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【算法题】多源BFS

多源BFS将所有满足条件的起点同时入队(视为“第0层”),再按层扩散,能高效解决“多个源点到网格中各点的最短距离”“全局最短/最长距离”“边界连通域标记”等问题。其核心优势是:仅需一次遍历即可完成所有源点的扩散,时间复杂度与单源BFS一致(O(mn)O(mn)O(mn)),远优于“对每个点做单源BFS”的暴力解法(O((mn)2)O((mn)^2)O((mn)2))。本文通过4道经典多源BFS题目,拆解多源BFS的核心框架与场景化适配技巧。

一、01矩阵(更新矩阵)

题目描述:给定一个由01组成的矩阵mat,将每个1替换为到最近0的最短距离,0保持不变,返回更新后的矩阵。

核心思路:多源BFS求最短距离
普通单源BFS只能求“一个0”到各点的距离,而本题需要“所有0”到各1的最短距离——将所有0作为同时出发的起点(距离为0),入队后按层扩散,每个1第一次被访问时的距离,就是到最近0的最短距离(多源扩散保证了“最短”)。

代码解析

classSolution{intm,n;intdx[4]={0,0,1,-1};// 上下左右方向数组intdy[4]={1,-1,0,0};public:vector<vector<int>>updateMatrix(vector<vector<int>>&mat){m=mat.size(),n=mat[0].size();vector<vector<int>>dist(m,vector(n,-1));// 距离数组:-1表示未访问queue<pair<int,int>>q;// 步骤1:所有0作为起点入队,距离设为0for(inti=0;i<m;i++)for(intj=0;j<n;j++)if(mat[i][j]==0){dist[i][j]=0;q.push({i,j});}// 步骤2:多源BFS扩散while(q.size()){auto[a,b]=q.front();q.pop();for(inti=0;i<4;i++){intx=a+dx[i],y=b+dy[i];// 边界检查 + 未访问(保证第一次访问是最短距离)if(x>=0&&y>=0&&x<m&&y<n&&dist[x][y]==-1){dist[x][y]=dist[a][b]+1;// 邻接节点距离=当前+1q.push({x,y});}}}returndist;}};

关键细节

  • dist数组既记录距离,又充当“访问标记”(-1=未访问),无需额外开vis数组;
  • 多源同时扩散,确保每个1被“最近的0”先访问,距离即为最短。

二、飞地数量(numEnclaves)

题目描述:给定01矩阵,“飞地”是指无法从边界的1到达的内部1,求飞地的数量。

核心思路:反向多源BFS标记连通域
飞地的本质是“不与边界1连通的内部1”——反向思考:将所有边界的1作为多源起点,标记所有可达的1,最后统计未被标记的1的数量即为飞地数。

代码解析

classSolution{intdx[4]={0,0,1,-1};intdy[4]={1,-1,0,0};public:intnumEnclaves(vector<vector<int>>&grid){intm=grid.size(),n=grid[0].size();vector<vector<bool>>vis(m,vector<bool>(n));// 访问标记:是否与边界1连通queue<pair<int,int>>q;// 步骤1:所有边界的1作为起点入队并标记for(inti=0;i<m;i++)for(intj=0;j<n;j++)if(i==0||j==0||i==m-1||j==n-1)// 边界坐标{if(grid[i][j]==1){q.push({i,j});vis[i][j]=true;}}// 步骤2:多源BFS标记所有可达的1while(q.size()){auto[a,b]=q.front();q.pop();for(inti=0;i<4;i++){intx=a+dx[i],y=b+dy[i];// 边界检查 + 未标记 + 是1if(x>=0&&y>=0&&x<m&&y<n&&!vis[x][y]&&grid[x][y]==1){vis[x][y]=true;q.push({x,y});}}}// 步骤3:统计未被标记的1(飞地)intret=0;for(inti=0;i<m;i++)for(intj=0;j<n;j++)if(!vis[i][j]&&grid[i][j]==1)ret++;returnret;}};

关键细节

  • 反向多源的核心是“标记不需要的部分”,剩余未标记的即为目标;
  • 仅遍历边界坐标作为起点,避免无效遍历。

三、最高海拔(highestPeak)

题目描述:给定矩阵isWater(1=水域,0=陆地),要求为每个陆地分配海拔:

  1. 水域海拔为0;
  2. 相邻单元格海拔差≤1;
  3. 海拔尽可能大。

核心思路:多源BFS求“最远最近距离”
满足“相邻差≤1且海拔最大”的唯一解是:每个陆地的海拔 = 到最近水域的最短距离(多源BFS的天然结果)。这道题是“01矩阵”的语义变体,逻辑完全一致。

代码解析

classSolution{intdx[4]={0,0,1,-1};intdy[4]={1,-1,0,0};public:vector<vector<int>>highestPeak(vector<vector<int>>&isWater){intm=isWater.size(),n=isWater[0].size();vector<vector<int>>dist(m,vector(n,-1));// dist数组存储海拔queue<pair<int,int>>q;// 步骤1:所有水域(1)作为起点,海拔设为0for(inti=0;i<m;i++)for(intj=0;j<n;j++)if(isWater[i][j]==1){dist[i][j]=0;q.push({i,j});}// 步骤2:多源BFS扩散,海拔=最近水域距离+1while(q.size()){auto[a,b]=q.front();q.pop();for(inti=0;i<4;i++){intx=a+dx[i],y=b+dy[i];if(x>=0&&y>=0&&x<m&&y<n&&dist[x][y]==-1){dist[x][y]=dist[a][b]+1;q.push({x,y});}}}returndist;}};

关键细节

  • 语义转换:“海拔”=“到最近水域的最短距离”,完全复用01矩阵的多源BFS逻辑;
  • 无需额外条件,多源扩散的结果天然满足“相邻差≤1”和“海拔最大”。

四、海洋陆地最远距离(maxDistance)

题目描述:给定01矩阵(1=陆地,0=海洋),求海洋到最近陆地的最远距离;若全是陆地/全是海洋,返回-1。

核心思路:多源BFS求全局最大最短距离
所有陆地作为多源起点,计算每个海洋到最近陆地的最短距离,最后取这些距离的最大值即为答案。

代码解析

classSolution{intdx[4]={0,0,1,-1};intdy[4]={1,-1,0,0};public:intmaxDistance(vector<vector<int>>&grid){intm=grid.size(),n=grid[0].size();vector<vector<int>>dist(m,vector(n,-1));queue<pair<int,int>>q;// 步骤1:所有陆地(1)作为起点入队,距离设为0for(inti=0;i<m;i++)for(intj=0;j<n;j++)if(grid[i][j]==1){dist[i][j]=0;q.push({i,j});}// 步骤2:多源BFS计算最短距离,同时记录最大值intret=-1;while(q.size()){auto[a,b]=q.front();q.pop();for(inti=0;i<4;i++){intx=a+dx[i],y=b+dy[i];if(x>=0&&y>=0&&x<m&&y<n&&dist[x][y]==-1){dist[x][y]=dist[a][b]+1;q.push({x,y});ret=max(ret,dist[x][y]);// 更新最大距离}}}returnret;// 全陆地时ret=-1,全海洋时也为-1,符合要求}};

关键细节

  • 无需额外遍历矩阵找最大值,在BFS过程中实时更新即可;
  • 边界条件自然满足:全陆地时没有海洋被访问,ret保持-1;全海洋时q初始为空,ret也为-1。

多源BFS通用框架总结

// 通用框架1.初始化:-距离/访问数组(dist/vis):-1/False 表示未访问;-队列q,将所有满足条件的多源起点入队,并初始化dist/vis;2.多源扩散:while(队列非空){取出队首节点(a,b);遍历四个方向: 计算邻接节点(x,y);if(边界合法&&未访问){更新dist/vis=当前节点值+1/True;入队(x,y);(可选)更新目标值(如最大距离、计数等);}}3.结果计算:-最短距离类:直接返回dist数组;-连通域标记类:统计未标记的节点数;-最大距离类:返回BFS中记录的最大值;
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 5:52:20

SiameseUIE在招聘简章解析中的应用:职位、要求、薪资、地点四维抽取

SiameseUIE在招聘简章解析中的应用&#xff1a;职位、要求、薪资、地点四维抽取 1. 为什么招聘简章解析需要新思路&#xff1f; 你有没有遇到过这样的场景&#xff1a;HR每天收到上百份招聘简章&#xff0c;要手动从PDF、Word或网页里一条条复制“岗位名称”“学历要求”“月…

作者头像 李华
网站建设 2026/6/9 23:58:16

Emotion2Vec+ Large实战体验:上传音频秒出9种情绪结果

Emotion2Vec Large实战体验&#xff1a;上传音频秒出9种情绪结果 1. 这不是“听个音调猜心情”&#xff0c;而是真正能读懂语音情绪的AI系统 你有没有过这样的经历&#xff1a;听一段客户录音&#xff0c;反复回放三遍&#xff0c;还是拿不准对方是真满意还是客气敷衍&#x…

作者头像 李华
网站建设 2026/6/10 16:34:39

HeyGem模型保存路径揭秘,方便后期调用

HeyGem模型保存路径揭秘&#xff0c;方便后期调用 HeyGem数字人视频生成系统在实际部署和二次开发中&#xff0c;一个常被忽略却极为关键的问题是&#xff1a;模型文件到底存在哪&#xff1f; 很多开发者在完成首次运行后&#xff0c;能顺利生成视频&#xff0c;但一旦想更换模…

作者头像 李华
网站建设 2026/6/14 14:22:36

保姆级教程:用ms-swift和GSPO实现多候选排序优化

保姆级教程&#xff1a;用ms-swift和GSPO实现多候选排序优化 在实际业务中&#xff0c;我们常常遇到这样的问题&#xff1a;模型生成的不是单一答案&#xff0c;而是多个候选结果——比如搜索引擎返回的Top5网页、客服系统生成的3种回复话术、编程助手提供的4种解法、RAG系统召…

作者头像 李华
网站建设 2026/6/10 17:33:57

告别手动操作!Open-AutoGLM让AI帮你搞定手机日常任务

告别手动操作&#xff01;Open-AutoGLM让AI帮你搞定手机日常任务 你有没有过这样的时刻&#xff1a; 刚下班想点个外卖&#xff0c;却在美团里翻了5分钟没找到想吃的&#xff1b; 朋友发来小红书博主链接&#xff0c;你得手动复制ID、打开APP、粘贴搜索、再点关注&#xff1b;…

作者头像 李华
网站建设 2026/6/15 11:16:57

如何用Qwen3-1.7B打造教育类AI应用?真实项目复现

如何用Qwen3-1.7B打造教育类AI应用&#xff1f;真实项目复现 1. 为什么教育场景特别需要Qwen3-1.7B&#xff1f; 你有没有遇到过这些情况&#xff1a; 学校想给学生配一个智能学习助手&#xff0c;但云API调用费用太高&#xff0c;一个年级每月就要上万元&#xff1b;教育机…

作者头像 李华