743.Network Delay Time
There are N
network nodes, labelled 1 to N
.
Given times
, a list of travel times as directed edges times[i] = (u, v, w)
, where u
is the source node, v
is the target node, and w
is the time it takes for a signal to travel from source to target.
Now, we send a signal from a certain node K
. How long will it take for all nodes to receive the signal? If it is impossible, return -1
.
Note
N
will be in the range[1, 100]
.K
will be in the range[1, N]
.- The length of times will be in the range
[1, 6000]
. - All edges
times[i] = (u, v, w)
will have1 <= u
,v <= N
and1 <= w <= 100
.
思路
题目是很典型的求一个有向图中,一个点到其他点的最短路径问题,只是输出有点小变化,把到其他点的最短路径中的最大值输出。那么问题就很简单啦,就是怎么求有向图中的最短路径。
在大一学习离散数学时,求有向图最短路径我们使用的是弗洛伊德算法(Floyd-Warshall Algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。但既然算法课教了新的算法,我也就尝试一下吧。
迪杰斯特拉算法(Dijkstra Algorithm),是一个应用最为广泛的单源最短路径算法,也是一个非常经典的贪心算法,因为它利用了已知最短路径来构建一个所有点的优先队列,以此来减少运算的次数,算法的时间复杂度为O(n2),n
为点的个数。
伪代码
input:Graph G = (V, E), directed or undirected;
positive edge lengths l; vertex s∈V
output:For all vertices u reachable from s, dist(u) is set to the distance from s to u.
for all u∈V:
dist(u) = ∞
prev(u) =nil (记录路径的前一个点,在这道题目中并不需要用到)
dist(s) = 0
H = makequeue(V) (using dist-values as keys)
while H is not empty:
u = deletemin(H)
for all edges (u, v)∈E:
if dist(v) > dist(u) + l(u, v):
dist(v) = dist(u) + l(u, v)
pre(v) = u
decreasekey(H, v)
代码
按照伪代码一步一步实现的话基本就没什么问题了,题目的提示是挺长的,但都是在说各个变量取值范围,方便我们定义数组的大小而已,有很多本应该告诉做题者的信息都没有提及到,我就说一下这题比较坑的地方。第一点,对于N个点的图,它的编号是从1
到n
的,并不是我们习惯的0
到n-1
,因为没有样例,提交一次看出错提示才能发现这一点。最坑最坑的就是作为参数传进来表示边的二维数组,一开始我还以为是图的邻接矩阵,结果交了几遍出现好多次数组越界问题才发现是错的,全部代码都要重新写一遍。这个二维数组实际上是一个边的集合,如下:
如何表示
u
到v
的距离为l
:
time [i
] [0
] =u
time [i
] [1
] =v
time [i
] [2
] =l
其中i
的取值范围为[0..n-1]
,n
为边的个数
class Solution {
public:
//更新优先队列的函数
void updateH(vector<int>& H, int v, int* dist)
{
for (int i = 0; i < H.size(); i++)
if (H[i] == v)
{
int j = i - 1;
while (j >= 0 && dist[v] < dist[H[j]])
{
H[j + 1] = H[j];
H[j] = v;
j--;
}
break;
}
}
int networkDelayTime(vector<vector<int>>& times, int N, int K)
{
int ans;
vector<int> H; //点的优先队列
int dist[105]; //记录已知最短路径的数组
//把距离初始化为“无穷”,源点到自身的距离自然为0
for (int i = 0; i < 105; i++)
dist[i] = 200;
dist[K] = 0;
//初始化优先队列,把源点放在队列头
for (int i = 1; i <= N; i++)
H.push_back(i);
for (int i = 0; i < N; i++)
for (int j = i + 1; j < N; j++)
if (dist[H[i]] > dist[H[j]])
{
int temp = H[i];
H[i] = H[j];
H[j] =temp;
}
while ( !H.empty() )
{
int u = H[0];
H.erase(H.begin());
for (int i = 0; i < times.size(); i++)
if (times[i][0] == u && (dist[times[i][1]] > dist[u] + times[i][2]) )
{
//每次更改现有最短路径,都要更新优先队列
dist[times[i][1]] = dist[u] + times[i][2];
updateH(H, times[i][1], dist);
}
}
//输出
ans = -1;
for (int i = 1; i <= N; i++)
{
if (dist[i] > ans) ans = dist[i];
if (dist[i] == 200)
{
ans = -1;
break;
}
}
return ans;
}
};