本文涉及知识点
LeetCode743. 网络延迟时间
有 n 个网络节点,标记为 1 到 n。
给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。
现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。
示例 1:
输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2
示例 2:
输入:times = [[1,2,1]], n = 2, k = 1
输出:1
示例 3:
输入:times = [[1,2,1]], n = 2, k = 2
输出:-1
提示:
1 <= k <= n <= 100
1 <= times.length <= 6000
times[i].length == 3
1 <= ui, vi <= n
ui != vi
0 <= wi <= 100
所有 (ui, vi) 对都 互不相同(即,不含重复边)
稠密图单源最短路径
本题本质是求:单源最短路径。由于本题是稠密图故用朴素迪氏单源路径。
时间复杂度:O(nn)
由于本题解,主要讲解BFS,故只简述原理:
dis[x]记录x到k的最短距离,将dis按升序排序后变成dis1。有如下性质:
dis[i]的最短路径任何节点i1,dis[i1]一定小于等于dis[i]。即:我们按dis[i]从小到大处理,一定可以保证无后效性。
思路:
处理cur节点时:更新所有和cur直接相连节点的dis。注意:如果新dis大于旧dis,则不更新。
未处理节点中寻找,寻找dis 最小的的节点开始处理。如果不存在,即所有和源点连接的节点都已经处理完毕,则结束。
BFS
错误解法
∀
x
i
n
\forall x \quad in
∀xin leves[i] , x到k的最短路径经过i个点。dis[i] 记录i到k的最短距离。
利用数学归纳法来证明:
如果i等于0,leves[0] = {k}。
i>1,则i的最短路径的倒数第二个点x1:一定属于leves[i-1]
故按leves[i]的顺序BFS,可保证无后效性。
时间复杂度:O(nn)
错误原因:
经过一个节点到c的记录是3,经过两个节点到c的距离是2。
某节点x可能经过i+1个节点比经过i1更短,需要重新枚举。
正确解法
处理完leves[0],c属于leves[1],处理完leves[1],c属于leves[2]。极端情况:
n个节点加入n次leves,故空间复杂度:O(nn)
每个leves元素的后续节点处理时间复杂度:O(n)
故总时间复杂度:O(nnn),本题能过。
BFS的状态:leves[i]的任意元素x,从k到x存在经过i个节点的路径。
BFS的后续状态:next和cur相连,且dis[cur]+ dis(cur,next) <= dis[next]。
BFS的初始值:leves[0] = {k},dis[k]=0,其它dis为1e6。
BFS返回值:max(dis),如果为1e6,则返回-1。
BFS重复状态处理:leves可以有重复元素,leves[i]没重复元素。
注意:有向图 节点编号从1开始。
代码
核心代码
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
vector < vector<pair<int, int>>> vNeiBo(n);
for (const auto& v : times) {
vNeiBo[v[0] - 1].emplace_back(v[1] - 1, v[2]);
}
const int iNotMay = 1e6;
vector<int> dis(n, iNotMay);
dis[k-1] = 0;
vector<unordered_set<int>> leves = { {k-1} };
for (int i = 0; i < leves.size(); i++) {
unordered_set<int> nexts;
for (const auto& cur : leves[i]) {
for (const auto& [next, w] : vNeiBo[cur]) {
const int iNew = dis[cur] + w;
if (iNew < dis[next]) {
dis[next] = iNew;
nexts.emplace(next);
}
}
}
if (nexts.empty()) { break; }
leves.emplace_back(nexts);
}
const int iMax = *std::max_element(dis.begin(), dis.end());
return (iNotMay != iMax) ? iMax : -1;
}
};
单元测试
TEST_METHOD(TestMethod1)
{
times = { {2,1,1},{2,3,1},{3,4,1} }, n = 4, k = 2;
auto res = Solution().networkDelayTime(times, n, k);
AssertEx(2, res);
}
TEST_METHOD(TestMethod2)
{
times = { {1,2,1} }, n = 2, k = 1;
auto res = Solution().networkDelayTime(times, n, k);
AssertEx(1, res);
}
TEST_METHOD(TestMethod3)
{
times = { {1,2,1} }, n = 2, k = 2;
auto res = Solution().networkDelayTime(times, n, k);
AssertEx(-1, res);
}
如果有不明白的,请加文末QQ群。
扩展阅读
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
相关推荐
我想对大家说的话 |
---|
《喜缺全书算法册》以原理、正确性证明、总结为主。 |
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。