_莫相逢

导航

Dijkstra 算法求最短路径

 

 以上是一个有向无环图,从V1到V2所花费的代价是2,从V1到V3的代价是3,...,以此类推,求出从V1到其他各个点的最短路径。

Dijkstra思路:

  1. 建立两个容器,容器S中装着已经求出最短路径的顶点,初始时只有V1,另外一个容器U装着V1到其他顶点的代价,初始时都为无穷大。

  2. 在图中遍历与V1直接相连的顶点V2和V3,发现(V1,V3)=3是最小的,此时将V3加入容器S,并且将V3移出U,得 S={V1=0,V3=3},U={V2=4,V4=∞,V5=∞,V6=∞}

  3. 以V3为中点,更新U中的其他点到V1的距离,取最小值。如 (V1,V3) + (V3,V4) = 3+3 = 6 < U[V4]=∞,所以U[V4]=6,依次类推,U[V5]=13,的U={V2=4,V4=6,V5=13,V6=∞}

  4. 找出U中最小的值,U[V2]=4,将V2加入到容器S中,并从U中移出,得 S={V1=0,V3=3,V2=4},U={V4=6,V5=13,V6=∞}

  5. 以V2为中点,更新U中的值,发现V4不用更新,因为(V1,V2)+(V2,V4)=10 < U[V4]=6,但是要更新V5,因为(V1,V2)+(V2,V5)=11 < U[V5]=13,得U={V4=6,V5=11,V6=∞}

  6. 找出U中最小的值,U[V4]=6,将V4加入到容器S中,并从U中移出,S={V1=0,V3=3,V2=4,V4=6}, U={V5=11,V6=∞}

  7. 以V4为中点,更新U中的值,发现(V1,V4)+(V4+V5)=6+2=8 < U[V5]=11,需要更新V5,此外,(V1,V4)+(V4,V6)=6+8=14 < U[V6]=∞ 也需要更新V6, 得出,U={V5=8,V6=14}

  8. 从U中找到最小值,U[V5]=8,将V5加入到容器S中,并从U中移出,得S={V1=0,V3=3,V2=4,V4=6,V5=8},U={V6=14}

  9. 以V5为中心,更新U中的值,发现(V1,V5)+(V5,V6)=8+5=13 < U[V6]=14,所以更新U={V6=13}

  10. 将剩下的V6加入到容器S中,遍历结束。此时,容器S中就是从V1到各个顶点的最小值。

 以上的4~5、5~6、7~8 都是重复的行为,因为总结出遍历规律:

if (V1,Vx) + (Vx, Vy) < U[Vy]

  U[Vy] = (V1,Vx) + (Vx,Vy)

这也是Dijkstra的核心思想。

时间复杂度

Dijkstra 算法的时间花费主要体现在重复的4~5步骤中,也就是不断的遍历顶点和边数,所有应该为O(V * E) ,近似可以等于O(E^2)

LeetCode试题

743. 网络延迟时间

有 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

 

C#实现解题:

 1         public int NetworkDelayTime(int[][] times, int n, int k)
 2         {
 3             int ans = 0;
 4             int len = n;
 5             int[] s = new int[n+1];
 6             s[k] = 0;
 7             Dictionary<int, int> u = new Dictionary<int, int>();
 8             
 9             //初始化U的各个节点为无穷大
10             for(int i = 1; i <= n; ++i)
11             {
12                 if (i != k)
13                 {
14                     u.Add(i, Int32.MaxValue);
15                 }
16             }
17             
18             //找出直接与K相邻的点,并更新U
19             for (int i = 0; i < times.Length; ++i)
20             {
21                 var arr = times[i];
22                 if (arr[0] == k)
23                 {
24                     u[arr[1]] = arr[2];
25                 }
26             }
27 
28             len--;
29 
30             while (len > 0)
31             {
32                 int minTemp = Int32.MaxValue;
33                 int index = -1;
34                 var uIt = u.GetEnumerator();
35                 while (uIt.MoveNext())
36                 {//找到U中最小的点
37                     if (uIt.Current.Value < minTemp)
38                     {
39                         minTemp = uIt.Current.Value;
40                         index = uIt.Current.Key;
41                     }
42                 }
43 
44                 if (index <= -1)
45                 {
46                     return -1;
47                 }
48 
49                 s[index] = minTemp;
50                 u.Remove(index);
51                 if (ans < minTemp)
52                 {
53                     ans = minTemp;
54                 }
55 
56                 if (u.Count <= 0)
57                 {
58                     break;
59                 }
60                 
61                 //以index点为中心,更新U中的点的值
62                 for (int i = 1; i <= n; ++i)
63                 {
64                     for (int j = 0; j < times.Length; ++j)
65                     {
66                         int[] timeArr = times[j];
67                         if (timeArr[0] == index && timeArr[1] == i && u.ContainsKey(i) && s[index] + timeArr[2] < u[i])
68                         {
69                             u[i] = s[index] + timeArr[2];
70                         }
71                     }
72                 }
73 
74                 len--;
75 
76             }
77 
78             return ans;
79         }

 

posted on 2022-06-19 15:46  莫晓风  阅读(82)  评论(0编辑  收藏  举报