《算法竞赛从入门到国奖》算法基础:搜索-多源BFS

💡Yupureki:个人主页

✨个人专栏:《C++》 《算法》


🌸Yupureki🌸的简介:


目录

前言

[1. 矩阵距离](#1. 矩阵距离)

算法原理

实操代码

[2. 刺杀大使](#2. 刺杀大使)

算法原理

实操代码


前言

当问题中只存在一个起点时,这时的最短路问题就是单源最短路问题。而当问题中存在多个起点而不是单一起点时,这时的最短路问题就是多源最短路问题。

多源最短路的解决方案就是把这些源点汇聚在一起 ,当成一个"超级源点"。然后从这个"超级源点"开始,处理最短路问题。

  1. 初始化的时候,把所有的源点都加入到队列里面;
  2. 然后正常执行bfs的逻辑即可。

也就是初始化的时候,比普通的bfs多加入几个起点。

1. 矩阵距离

题目链接:

矩阵距离

算法原理

正难则反:

  • 如果针对某一个点,直接去找最近的1,我们需要对所有的0都来一次6fs,这个时间复杂度是接受不了的。
  • 但是我们如果反着来想,从1开始向外扩展,每遍历到一个0就更新一下最短距离。这样仅需一次bfs,就可以把所有点距离1的最短距离更新出来。

正难则反是很重要的思想,后续还有很多题可以用到这个思想。

由于1的数量很多,我们在初始化阶段把所有1的坐标加入到队列中,然后正常bfs。

实操代码

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int n, m;
vector<vector<int>> v;
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };

void bfs()
{
    vector<vector<int>> ret(n, vector<int>(m, 0));
    queue<pair<int, int>> q;
    v.resize(n);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            char num; cin >> num;
            v[i].push_back(num - '0');
            if (num == '1')//把所有的1都加入队列中
                q.push({ i,j });
        }
    }
    while (q.size())
    {
        auto p = q.front();
        q.pop();
        int a = p.first;
        int b = p.second;
        for (int k = 0; k < 4; k++)
        {
            int x = a + dx[k];
            int y = b + dy[k];
            if (x < 0 || x >= n || y < 0 || y >= m || v[x][y] == 1 || ret[x][y])
                continue;
            ret[x][y] = ret[a][b] + 1;
            q.push({ x,y });
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cout << ret[i][j] << " ";
        }
        cout << endl;
    }
}

int main()
{
    cin >> n >> m;
    bfs();
    return 0;
}

2. 刺杀大使

题目链接:

P1902 刺杀大使 - 洛谷

算法原理

关键词:所有最大值中的最小值

这是很经典二分答案的题目说法,而我们也能发现对于所有的伤害值,一定存在一个界限x,使得

  • 大于或等于x的伤害值一定能通过机关
  • 小于x的伤害值一定不能通过机关

因此我们通过二分枚举答案,对于每一个二分结果,进行检查,是否能通过机关

具体如何判断通过,我们发现可以从第一行任意一个格子出发,因此我们把第一行所有的格子都加入节点,然后通过BFS判断

实操代码

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int n, m;
vector<vector<int>> v;
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };

bool bfs(int ret)
{
    queue<pair<int, int>> q;
    vector<vector<bool>> mem(n, vector<bool>(m, false));
    for (int j = 0; j < m; j++)
    {
        q.push({ 0,j });//将第一行所有的格子都加入队列
    }
    while (q.size())
    {
        auto p = q.front();
        q.pop();
        int a = p.first;
        int b = p.second;
        if (a == n - 1)
            return true;
        for (int k = 0; k < 4; k++)
        {
            int x = a + dx[k];
            int y = b + dy[k];
            if (x < 0 || x >= n || y<0 || y >= m || mem[x][y] || v[x][y] > ret)
                continue;
            mem[x][y] = true;
            q.push({ x,y });
        }
    }
    return false;
}

int main()
{
    int left = 0;
    int right = 0;
    cin >> n >> m;
    v.resize(n);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            int num; cin >> num;
            v[i].push_back(num);
            if (num > right)
                right = num;
        }
    }
    while (left < right)//二分答案
    {
        int mid = (left + right) / 2;
        if (bfs(mid)) right = mid;
        else left = mid + 1;
    }
    cout << left;
    return 0;
}
相关推荐
不正经学生10 分钟前
C语言大小端字节序:内存里字节的排列顺序
c语言·开发语言·arm开发·c++·算法·c#
小则又沐风a1 小时前
负载均衡式在线OJ---------第二幕
linux·c++·后端
a3535413821 小时前
C++项目如何架构优化
java·c++·架构
键盘会跳舞1 小时前
C++:智能指针源码级深度拆解——从 RAII 思想到引用计数的内存安全体系
c++·智能指针·unique_ptr·shared_ptr·weak_ptr
依然鸣1 小时前
PTA团体程序设计天梯赛L2真题讲解L2-001-004
经验分享·学习·算法·深度优先·pat考试
一米阳光86611 小时前
软考(中级)软件设计师核心笔记(8)数据结构——图
数据结构·笔记·职场发展·软考·软件设计师·中级职称
SNAKEpc121381 小时前
OpenGL(十三)- Mip贴图
c语言·c++·图形渲染·贴图
杨航 AI3 小时前
** AI 面试算法 50 题清单**,不是单纯的 LeetCode 题号列表,而是按照“**考察概率 × 面试价值 × 你当前准备方向**”排序
算法·leetcode·面试
m0_720245019 小时前
1543.统计好三元组(简单)
开发语言·算法
To_OC10 小时前
LC 560 和为 K 的子数组:前缀和配哈希表,这对组合我是真的服了
javascript·算法·程序员