Week4
上周犯了个小错误,在写第3周的博客时,不小心直接在第2周的博客上改了,然后第2周的博客直接被第3周的覆盖了,所以这周写2篇补回来。
Graph
question source: Network Delay Time
question description
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 have 1 <= u, v <= N and 1 <= w <= 100.
这周学习了图的路径,这是一个有向图类型的题目,问的是从图中的一个点,发出一个信号,要多长时间,所有点能收到信号。很明显,这就是求一个点到其他点的最短距离,而这些距离中的最大值,就是我们要求的。很明显就是用这周学的迪杰斯特拉算法,下面就些实现了这个算法。
迪杰斯特拉算法伪代码如下
Function Dijkstra(G, w, s)
for each vertex v in V[G]
d[v] := infinity // 开始最短距离设为无穷
previous[v] := undefined // 用于保存前一个节点
d[s] := 0 // 出发点到出发点的距离为0
S := empty set
Q := set of all vertices
while Q is not an empty set
u := Ectract_Min(Q) // 把集合Q里的距离最小的删除
S.append(u)
for each edge outgoing from u as (u, v)
if d[v] > d[u] + w(u, v) // 更新
d[v] := d[u] + w(u, v)
previous[v] := u
实现的代码如下
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
//dijkstra
int dist[N + 1];
int q[N + 1];
for(int i = 1; i <= N; i++){
dist[i] = -1;
q[i] = 1;
}
dist[K] = 0;
//S:empty
//Q: all set
int n = N;
while(n != 0){
int v = 0;
//find min dist
int min = -1;
for(int i = 1; i <= N; i++){
if(q[i] == 1){
if(min == -1 && dist[i] != -1){
min = dist[i];
v = i;
}else if(dist[i] < min && dist[i] != -1){
min = dist[i];
v = i;
}
}
}
//The grap is not connected
if(v == 0) return -1;
for(int i = 0; i < times.size(); i++){
if(times[i][0] == v){
int next = times[i][1];
if(dist[next] == -1){
dist[next] = times[i][2] + dist[v];
}else if(dist[next] > times[i][2] + dist[v]){
dist[next] = times[i][2] + dist[v];
}
}
}
q[v] = 0;
n--;
}
int answer = 0;
for(int i = 1; i <= N; i++){
if(dist[i] > answer){
answer = dist[i];
}
}
return answer;
}
};
迪杰斯特拉算法要求我们实现一个优先队列,算法运行时间严重依赖于优先队列的实现方式。我的代码是使用一个无序数组q来实现,insert操作或者decreasekey操作是很快的,只要修改一个键值就行了,耗费的时间是O(1),而deletemin操作需要对整个数组进行扫描,从而将耗费线性时间。总的算法复杂度为 O ( ∣ V ∣ 2 ) O(|V|^2) O(∣V∣2)
上课说了,优先队列也可以采用二分堆来实现。元素存储在一个完全二叉树上,树中任意节点的键值必须小于等于其后裔节点的键值。insert时,将元素置于树的最底端,然后让它“冒泡”,decreasekey时,从当前位置直接“冒泡”,而deletemin时,直接返回根节点的键值。删除根节点后,取出树的最后一个节点,置于树根,然后“向下过滤”。完全二叉树直接用数组实现,总的算法复杂度为 O ( ( ∣ V ∣ + ∣ E ∣ ) l o g ∣ V ∣ ) O((|V| + |E|)log|V|) O((∣V∣+∣E∣)log∣V∣)