743. 网络延迟时间 - 力扣(LeetCode)
计算的是要是所有节点都接收到信号经历的时长,所以必然是需要遍历整个图的,并且遍历的时候需要记录每个节点接收到信号经历的时长,时长也就是该节点到起始节点 K 的最短路径长度。
那么我们可以使用dijkstra算法计算每个节点到起始节点 K 的最短路径,最后取所有路径中最大的那个即可。
数据结构与算法:44 |最短路径:地图软件如何计算最优出行路径?_zj-CSDN博客
引入两个集合 S 和 U,S 的作用是记录已求出最短路径的顶点(以及相应的最短路径长度,可以使用pair),而U的作用记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。
初始情况下,S中只有起点 K(对应最短路径为0,自己到自己);U中是除 K 之外的所有顶点,并且U中顶点的路径是: 起点 K 到该顶点的路径(初始化为 INT_MAX)。
while循环里主要做两件事:
直到遍历完所有顶点,循环结束。
对于寻找最小路径值这一操作,可以使用优先级队列进行优化:
class Solution {
public:
int networkDelayTime(vector>& times, int N, int K) {
vector distance(N+1, INT_MAX);//起点K到每个节点的距离
vector flags(N+1, false);//记录节点是否已经计算出最短距离
unordered_map>> adj;//邻接表
//piar第一个为距离,第二个为节点编号
for(const auto &v : times) adj[v[0]].push_back({v[2], v[1]});//生成邻接表
//小顶堆,pair第一个元素为节点K到该节点的距离,第二个是该节点的编号
priority_queue, vector>, greater>> q;
q.push({0, K});
distance[K] = 0;//自己到自己的距离为0
while(!q.empty()){
auto t = q.top();
q.pop();
int cur = t.second, dis = t.first;//cur表示当前节点,dis表示节点K到当前节点的距离
if(dis == INT_MAX) return -1;//队列头部最小值也为INT_MAX,说明信号无法达到
if(flags[cur]) continue;//之前处理过
flags[cur] = true;
//考虑与当前节点cur相连(指向)的节点,并更新节点K到他们的距离
for(const auto &p : adj[cur]){//adj[cur]映射到vector>
//找到更短的距离,需要更新
if(distance[p.second] > dis + p.first){//dis(p.second, k) > dis(k, cur) + dis(cur, p.second),dis代表两者距离
distance[p.second] = dis + p.first;
q.push({distance[p.second], p.second});//{K到该节点的距离,该节点的编号}
}
}
}
int res = *max_element(distance.begin()+1, distance.end());
return res == INT_MAX ? -1 : res;
}
};
如果不使用优先级队列,需要手动寻找最小值,不过思路都是一样的:
class Solution {
public:
int networkDelayTime(vector>& times, int N, int K) {
vector distance(N+1, INT_MAX);//起点K到每个顶点的距离
vector flags(N+1, false);//记录顶点是否已经计算出最短距离
unordered_map>> adj;//邻接表
//piar第一个为距离,第二个为节点编号
for(const auto &v : times) adj[v[0]].push_back({v[2], v[1]});//生成邻接表
distance[K] = 0;//自己到自己的距离为0
for(int i = 0; i < N-1; ++i){//循环次数最多为N-1次(因为起点k已激活)
//遍历所有的顶点,寻找距离起点的距离最小的那个
int t = -1;
for(int j = 1; j <= N; ++j){//编号从1开始,第一位没有使用
if(!flags[j] && (t == -1 || distance[t] > distance[j])) t = j;
}
flags[t] = true; //该顶点的最短路径已确定
//更新与顶点t相连的节点到起点的距离,其他不相连的顶点不用更新
for(const auto &p : adj[t]){
if(distance[p.second] > distance[t] + p.first){
distance[p.second] = distance[t] + p.first;
}
}
}
int res = *max_element(distance.begin()+1, distance.end());
return res == INT_MAX ? -1 : res;
}
};
优化一下:
class Solution {
public:
int networkDelayTime(vector>& times, int N, int K) {
vector distance(N+1, INT_MAX);//起点K到每个顶点的距离
vector flags(N+1, false);//记录顶点是否已经计算出最短距离
unordered_map>> adj;//邻接表
//piar第一个为距离,第二个为节点编号
for(const auto &v : times) adj[v[0]].push_back({v[2], v[1]});//生成邻接表
distance[K] = 0;//自己到自己的距离为0
for(int i = 0; i < N; ++i){//循环次数最多为N-1次(因为起点k已激活)
//遍历所有的顶点,寻找距离起点的距离最小的那个
int t = -1;
for(int j = 1; j <= N; ++j){//编号从1开始,第一位没有使用
if(!flags[j] && (t == -1 || distance[t] > distance[j])) t = j;
}
flags[t] = true; //该顶点的最短路径已确定
if(distance[t] == INT_MAX) return -1;//最小值为INT_MAX,说明剩下的顶点都不可能和起点相连,永远接收不到信号
//更新与顶点t相连的节点到起点的距离,其他不相连的顶点不用更新
for(const auto &p : adj[t]){
if(distance[p.second] > distance[t] + p.first){
distance[p.second] = distance[t] + p.first;
}
}
}
return *max_element(distance.begin()+1, distance.end());
}
};