Upload
george-king
View
430
Download
3
Embed Size (px)
Citation preview
Weighted Graph Algorithms
Contents 最小生成树
Prim算法 并查集 Kruskal算法
最短路问题 Dijkstra 算法 Bellman-Ford 算法 Floyd 算法
网络流初步 最大流问题 最小费用最大流
最小生成树
Minimum Spanning Trees• Given: Connected, undirected, weighted graph, G• Find: Minimum - weight spanning tree, T• Example:
b c
a
d e f
5
11
0
3 1
7
-3
1
a
b c
fed
5
3 -31
0
Acyclic subset of edges(E) that connectsall vertices of G.
Generic Algorithm“Grows” a set A.
A is subset of some MST.
Edge is “safe” if it can be added to A without destroying this invariant.
Generic-MST(G, w)1 A := ;2 while A does not form a MST3 do find a safe edge (u, v) for A4 A := A {(u, v)}5 return A
Generic-MST(G, w)1 A := ;2 while A does not form a MST3 do find a safe edge (u, v) for A4 A := A {(u, v)}5 return A
Ücut partitions vertices intodisjoint sets, S and V – S.
b ca
d e f
5
11
0
3 1
7
-3
2
this edge crosses the cut
a light edge crossing cut(could be more than one)
Definitions
cut respects the edge set {(a, b), (b, c)}
one endpoint is in S and the other is in V – S.
no edge in the set crosses the cut
Proof:Let T be a MST that includes A.Case: (u, v) in T. We’re done.Case: (u, v) not in T. We have the following:
u y
x
v
edge in A
cut
shows edgesin T
Theorem 23.1 in CLRSTheorem 23.1: Let (S, V-S) be any cut that respects A, and let (u, v) be a light edge crossing (S, V-S). Then, (u, v) is safe for A.
Theorem 23.1: Let (S, V-S) be any cut that respects A, and let (u, v) be a light edge crossing (S, V-S). Then, (u, v) is safe for A.
(x, y) crosses cut.Let T´ = T - {(x, y)} {(u, v)}.
Because (u, v) is light for cut,w(u, v) w(x, y). Thus, w(T´) = w(T) - w(x, y) + w(u, v) w(T).
Hence, T´ is also a MST. So, (u, v) is safe for A.
In general, A will consist of several connected components.
Corollary
Corollary: If (u, v) is a light edge connecting one CC in (V, A)to another CC in (V, A), then (u, v) is safe for A.
Corollary: If (u, v) is a light edge connecting one CC in (V, A)to another CC in (V, A), then (u, v) is safe for A.
Example: Kruskal’s Algorithm
Figure: Kruskal’s Algorithm
Kruskal 算法
把所有边排序,记第 i 小的边为 e[i] (0<=i<m)
初始化 MST 为空初始化连通分量,让每个点自成为一个独立的连通分量for (int i=0; i<m; i++) if (e[i].u 和 e[i].v 不在同一个连通分量 ) { 把边 e[i] 加入 MST 合并 e[i].u 和 e[i].v 所在的连通分量 }
存储结构
int u[maxm],v[maxm],w[maxm];cin >> n >> m; // 输入 n 个顶点 , m 条边for(int e=0;e<m;e++) cin>>u[e]>>v[e]>>w[e];// 排序边int cmp(const int i, const int j){return w[i]<w[j];}int e[m];for(int i=0;i<m; i++) e[i] = i;sort(e, e+m, cmp);
MST-Kruskal(G, w)
1 A // initially A is empty
2 for each vertex v V[G] // line 2-3 takes O(V) time
3 do Make-Set(v) // create set for each vertex
4 sort the edges of E into nondecreasing order by weight w
5 for each edge (u,v) E, taken in nondecreasing order by weight
6 do if Find-Set(u) Find-Set(v) // u&v on different trees
7 then A A {(u,v)}
8 Union(u,v)
9 return A
Total running time is O(E lg E).
并查集
并查集 森林表示法:可以用森林来表示并查集。
森林里的每棵树代表一个集合。 树的根结点就是集合的代表元素。
数组表示的森林 Each entry p[i] in the array represents the parent
of element i, initially p[i] = -1. If i is a root, then p[i] = -1.
查找操作 查找一个元素 u ,只需顺着叶子到根结点的路径找
到 u 所在的根结点,也就确定 u 所在的集合。
Union Eight elements, initially in different sets
1 2 3 4 5 6 70
-1 -1 -1 -1 -1 -1 -1 -1
0 1 2 3 4 5 6 7
Union After union(4,5)
1 2 3 4
5
6 70
-1 -1 -1 -1 -1 4 -1 -1
0 1 2 3 4 5 6 7
Union After union(6,7)
1 2 3 4
5
0
-1 -1 -1 -1 -1 4 -1 6
0 1 2 3 4 5 6 7
6
7
Union After union(4,6)
1 2 3 4
5
0
-1 -1 -1 -1 -1 4 4 6
0 1 2 3 4 5 6 7
6
7
Union Codesint p[maxn];for(int i=0;i<n;i++) p[i] = -1;int find(int x) { return (p[x] == -1) ? x : find(p[x]);}int union(int x, int y){ p[y] = x;}
Quick-Find Now
1 2 3 4
5
0
-1 -1 -1 -1 -1 4 4 6
0 1 2 3 4 5 6 7
6
7
Quick-Find After find(7)
1 2 3 4
5
0
-1 -1 -1 -1 -1 4 4 4
0 1 2 3 4 5 6 7
6 7
Quick-Find
int p[maxn];for(int i=0;i<n;i++) p[i] = -1;int find(int x) { return (p[x] == -1) ? x : p[x]=find(p[x]);}int union(int x, int y){ p[y] = x;}
更高效的合并策略当 p[i] 值小于 0 ,表明 i 是所在树的根结点(所在集
合的代表元素)。这时用 -p[i] 值计 i 所在树的高度。合并时将矮树合并到高树。
int p[maxn];for(int i=0;i<n;i++) p[i] = -1;int find(int x) { return (p[x] < 0) ? x : p[x]=find(p[x]);}int union(int x, int y){ if (p[x]<p[y]) p[y] = x; //x higher than y else if (p[y]<p[x]) p[x] = y; //y higher than x else {p[y] = x; p[x]--;}}
Kruskal with disjoint setsint cmp(int i, int j) {return w[i]<w[j]};int p[maxn],r[maxm]; int find(int x) {return (p[x] == -1) ? x : p[x]=find(p[x]);}int union(int x, int y) { p[y] = x;}int Kruskal() { int ans = 0; for(int i=0;i<n;i++) p[i] = -1; for(int i=0;i<m;i++) r[i] = i; sort(r,r+m,cmp); for(int i=0;i<m;i++) { int e = r[i], x = find(u[e]), y = find(v[e]); if (x!=y) {ans += w[e]; union(x,y);} } return ans;}
Prim Algorithm
Prim’s Algorithm Builds one tree, so A is always a tree. Starts from an arbitrary “root” r . At each step, adds a light edge crossing cut (VA, V -
VA) to A. VA = vertices that A is incident on.
Prim’s Algorithm Uses a priority queue Q to find a light edge quickly. Each object in Q is a vertex in V - VA. Key of v is minimum weight of any edge (u, v), where u
VA. Then the vertex returned by Extract-Min is v such that
there exists u VA and (u, v) is light edge crossing (VA, V - VA).
Key of v is if v is not adjacent to any vertex in VA.
Q := V[G];for each u Q do
key[u] := od;key[r] := 0;[r] := NIL;while Q do
u := Extract - Min(Q);for each v Adj[u] do
if v Q and w(u, v) < key[v] then [v] := u;
key[v] := w(u, v)fi
odod
Q := V[G];for each u Q do
key[u] := od;key[r] := 0;[r] := NIL;while Q do
u := Extract - Min(Q);for each v Adj[u] do
if v Q and w(u, v) < key[v] then [v] := u;
key[v] := w(u, v)fi
odod
Complexity:Using binary heaps: O(E lg V). Initialization – O(V). Building initial queue – O(V). V Extract-Min’s – O(V lgV). E Decrease-Key’s – O(E lg V). Using Fibonacci heaps: O(E + V lg V).(see book)
Prim’s Algorithm
Note: A = {(v, [v]) : v v - {r} - Q}.
decrease-key operation
/* very similar to Dijkstra’s algorithm */
v1 v2
v6 v7
v3 v4 v5
2
4
2
1 3 10
7
58 4
61
Example of Prim’s Algorithm
Example of Prim’s Algorithm
b/ c/a/0
d/ e/ f/
5
11
0
3 1
7
-3
2
Q = a b c d e f 0
Not in tree
Example of Prim’s Algorithm
b/5 c/a/0
d/11 e/ f/
5
11
0
3 1
7
-3
2
Q = b d c e f 5 11
Example of Prim’s Algorithm
b/5 c/7a/0
d/11 e/3 f/
5
11
0
3 1
7
-3
2
Q = e c d f 3 7 11
Example of Prim’s Algorithm
b/5 c/1a/0
d/0 e/3 f/2
5
11
0
3 1
7
-3
2
Q = d c f 0 1 2
Example of Prim’s Algorithm
b/5 c/1a/0
d/0 e/3 f/2
5
11
0
3 1
7
-3
2
Q = c f 1 2
Example of Prim’s Algorithm
b/5 c/1a/0
d/0 e/3 f/-3
5
11
0
3 1
7
-3
2
Q = f -3
Example of Prim’s Algorithm
b/5 c/1a/0
d/0 e/3 f/-3
5
11
0
3 1
7
-3
2
Q =
Example of Prim’s Algorithm
0
b/5 c/1a/0
d/0 e/3 f/-3
5
3 1 -3
Variations on Minimum Spanning Trees Maximum Spanning Trees
Simply negating the weights of all edges and running Prim’s algorithm.
Minimum Product Spanning Trees We seek the spanning tree that minimizes the product
of edge weights. Since lg(ab)=lg(a) + lg(b), the mst on a graph whose
edge weights are replaced with their logarithms gives the answer.
Minimum Bottlenneck Spanning Tree Sometimes we seek a spanning tree that minimizes
the maximum edge weight over all such trees. Every MST has this property.
Single-Source Shortest Paths Given A single source vertex in a weighted, directed graph. Want to compute a shortest path for each possible destination. Similar to BFS.
We will assume either no negative-weight edges, or no reachable negative-weight cycles.
Algorithm will compute a shortest-path tree. Similar to BFS tree.
Outline
General Lemmas and Theorems. DAG algorithm. Dijkstra algorithm. Bellman-Ford algorithm.
Corollary: Let p = SP from s to v, where p = s u v. Then,δ(s, v) = δ(s, u) + w(u, v).
Corollary: Let p = SP from s to v, where p = s u v. Then,δ(s, v) = δ(s, u) + w(u, v).
General Results (Relaxation)Lemma 24.1: Let p = ‹v1, v2, …, vk› be a SP from v1 to vk. Then,pij = ‹vi, vi+1, …, vj› is a SP from vi to vj, where 1 i j k.
Lemma 24.1: Let p = ‹v1, v2, …, vk› be a SP from v1 to vk. Then,pij = ‹vi, vi+1, …, vj› is a SP from vi to vj, where 1 i j k.
So, we have the optimal-substructure property.
Bellman-Ford’s algorithm uses dynamic programming.
Dijkstra’s algorithm uses the greedy approach.
Let δ(u, v) = weight of SP from u to v.
p'
Lemma 24.10: Let s V. For all edges (u,v) E, we haveδ(s, v) δ(s, u) + w(u,v).
Lemma 24.10: Let s V. For all edges (u,v) E, we haveδ(s, v) δ(s, u) + w(u,v).
Relaxation
Initialize(G, s)for each v V[G] do
d[v] := ;[v] := NIL
od;d[s] := 0
Initialize(G, s)for each v V[G] do
d[v] := ;[v] := NIL
od;d[s] := 0
Relax(u, v, w)if d[v] > d[u] + w(u, v) then
d[v] := d[u] + w(u, v);[v] := u
fi
Relax(u, v, w)if d[v] > d[u] + w(u, v) then
d[v] := d[u] + w(u, v);[v] := u
fi
Algorithms keep track of d[v], [v]. Initialized as follows:
These values are changed when an edge (u, v) is relaxed:
Properties of Relaxation d[v], if not , is the length of some path from s to
v. d[v] either stays the same or decreases with
time Therefore, if d[v] = (s, v) at any time, this holds
thereafter Note that d[v] (s, v) always After i iterations of relaxing on all (u,v), if the
shortest path to v has i edges, then d[v] = (s, v).
Properties of RelaxationConsider any algorithm in which d[v], and [v] are first initializedby calling Initialize(G, s) [s is the source], and are only changed bycalling Relax. We have:
Lemma 24.11: ( v:: d[v] (s, v)) is an invariant.Lemma 24.11: ( v:: d[v] (s, v)) is an invariant.
Implies d[v] doesn’t change once d[v] = (s, v).
Proof:Initialize(G, s) establishes invariant. If call to Relax(u, v, w)changes d[v], then it establishes:
d[v] = d[u] + w(u, v) (s, u) + w(u, v) , invariant holds before call. (s, v) , by Lemma 24.10.
Corollary 24.12: If there is no path from s to v, thend[v] = δ(s, v) = is an invariant.
Corollary 24.12: If there is no path from s to v, thend[v] = δ(s, v) = is an invariant.
More Properties
Lemma 24.14: Let p = SP from s to v, where p = s u v.If d[u] = δ(s, u) holds at any time prior to calling Relax(u, v, w),then d[v] = δ(s, v) holds at all times after the call.
Lemma 24.14: Let p = SP from s to v, where p = s u v.If d[u] = δ(s, u) holds at any time prior to calling Relax(u, v, w),then d[v] = δ(s, v) holds at all times after the call.
p'
Proof:
After the call we have:d[v] d[u] + w(u, v) , by Lemma 24.13. = (s, u) + w(u, v) , d[u] = (s, u) holds. = (s, v) , by corollary to Lemma 24.1.
By Lemma 24.11, d[v] δ(s, v), so d[v] = δ(s, v).
Lemma 24.13: Immediately after relaxing edge (u, v) by callingRelax(u, v, w), we have d[v] d[u] + w(u, v).
Lemma 24.13: Immediately after relaxing edge (u, v) by callingRelax(u, v, w), we have d[v] d[u] + w(u, v).
Predecessor SubgraphLemma 24.16: Assume given graph G has no negative-weight cyclesreachable from s. Let G = predecessor subgraph. G is always atree with root s (i.e., this property is an invariant).
Lemma 24.16: Assume given graph G has no negative-weight cyclesreachable from s. Let G = predecessor subgraph. G is always atree with root s (i.e., this property is an invariant).
Proof:Two proof obligations:
(1) G is acyclic.(2) There exists a unique path from source s to each vertex in V.
Proof of (1):
Suppose there exists a cycle c = ‹v0, v1, …, vk›, where v0 = vk.We have [vi] = vi-1 for i = 1, 2, …, k.
Assume relaxation of (vk-1, vk) created the cycle.We show cycle has a negative weight.
Note: Cycle must be reachable from s. (Why?)
Proof of (1) (Continued)Before call to Relax(vk-1, vk, w):
[vi] = vi-1 for i = 1, …, k–1.
Implies d[vi] was last updated by “d[vi] := d[vi-1] + w(vi-1, vi)”for i = 1, …, k–1.
Implies d[vi] d[vi-1] + w(vi-1, vi) for i = 1, …, k–1.
Because [vk] is changed by call, d[vk] > d[vk-1] + w(vk-1, vk). Thus,
cycle!weight -neg. i.e., 0,)v,w(v ,]d[v]d[v Because
)v,w(v]d[v
))v,w(v](d[v]d[v
k
1ii1i
k
1i1i
k
1ii
k
1i
k
1ii1i1i
k
1i
k
1ii1i1ii
Proof of (2)Proof of (2):
( v: v V:: ( path from s to v)) is an invariant.
So, for any v in V, at least 1 path from s to v.
Show 1 path.
Assume 2 paths.
s u
y
x
z v
impossible!
Lemma 24.17Lemma 24.17: Same conditions as before. Call Initialize & repeatedlycall Relax until d[v] = δ(s, v) for all v in V. Then, G is a shortest-pathtree rooted at s.
Lemma 24.17: Same conditions as before. Call Initialize & repeatedlycall Relax until d[v] = δ(s, v) for all v in V. Then, G is a shortest-pathtree rooted at s.
Proof:
Key Proof Obligation: For all v in V, the unique simple path p froms to v in G (path exists by Lemma 24.16) is a shortest path from s to vin G.
Let p = ‹v0, v1, …, vk›, where v0 = s and vk = v.
We have d[vi] = δ(s, vi) d[vi] d[vi-1] + w(vi-1, vi)
Implies w(vi-1, vi) δ(s, vi) – δ(s, vi-1).
Proof (Continued)
)v, δ(s
)v, δ(s)v, δ(s
))v, δ(s)v, δ(s(
)v,w(v
w(p)
k
0k
1-ii
k
1i
k
1ii1i
So, p is a shortest path.
Bellman-Ford AlgorithmCan have negative-weight edges. Will “detect” reachable negative-weightcycles.
Initialize(G, s);for i := 1 to |V[G]| –1 do
for each (u, v) in E[G] doRelax(u, v, w)
odod;for each (u, v) in E[G] do
if d[v] > d[u] + w(u, v) thenreturn false
fiod;return true
Initialize(G, s);for i := 1 to |V[G]| –1 do
for each (u, v) in E[G] doRelax(u, v, w)
odod;for each (u, v) in E[G] do
if d[v] > d[u] + w(u, v) thenreturn false
fiod;return true
Time Complexityis O(VE).
Example
0
z
u v
x y
6
5
–3
9
7
7
8
–2
–42
Example
0
7
6
z
u v
x y
6
5
–3
9
7
7
8
–2
–42
Example
0
27
46
z
u v
x y
6
5
–3
9
7
7
8
–2
–42
Example
0
27
42
z
u v
x y
6
5
–3
9
7
7
8
–2
–42
Example
0
-27
42
z
u v
x y
6
5
–3
9
7
7
8
–2
–42
Another LookNote: This is essentially dynamic programming.
Let d(i, j) = cost of the shortest path from s to i that is at most j hops.
d(i, j) =
0 if i = s j = 0 if i s j = 0min({d(k, j–1) + w(k, i): i Adj(k)} {d(i, j–1)}) if j > 0
z u v x y 1 2 3 4 50 0 1 0 6 7 2 0 6 4 7 23 0 2 4 7 24 0 2 4 7 –2
j
i
Lemma 24.2Lemma 24.2: Assuming no negative-weight cycles reachable froms, d[v] = (s, v) holds upon termination for all vertices v reachablefrom s.
Lemma 24.2: Assuming no negative-weight cycles reachable froms, d[v] = (s, v) holds upon termination for all vertices v reachablefrom s.
Proof:
Consider a SP p, where p = ‹v0, v1, …, vk›, where v0 = s and vk = v.
Assume k |V| – 1, otherwise p has a cycle.
Claim: d[vi] = (s, vi) holds after the ith pass over edges.Proof follows by induction on i.
By Lemma 24.11, once d[vi] = (s, vi) holds, it continues to hold.
CorrectnessClaim: Algorithm returns the correct value.
(Part of Theorem 24.4. Other parts of the theorem follow easily from earlier results.)
Case 1: There is no reachable negative-weight cycle.
Upon termination, we have for all (u, v):d[v] = (s, v) , by Lemma 24.2 if v is reachable; d[v] = (s, v) = otherwise. (s, u) + w(u, v) , by Lemma 24.10. = d[u] + w(u, v)
So, algorithm returns true.
Case 2Case 2: There exists a reachable negative-weight cyclec = ‹v0, v1, …, vk›, where v0 = vk.
We have i = 1, …, k w(vi-1, vi) < 0. (*)
Suppose algorithm returns true. Then, d[vi] d[vi-1] + w(vi-1, vi) fori = 1, …, k. Thus,
i = 1, …, k d[vi] i = 1, …, k d[vi-1] + i = 1, …, k w(vi-1, vi)
But, i = 1, …, k d[vi] = i = 1, …, k d[vi-1].
Can show no d[vi] is infinite. Hence, 0 i = 1, …, k w(vi-1, vi).
Contradicts (*). Thus, algorithm returns false.
Shortest Paths in DAGs
Topologically sort vertices in G;Initialize(G, s);for each u in V[G] (in order) do
for each v in Adj[u] doRelax(u, v, w)
odod
Topologically sort vertices in G;Initialize(G, s);for each u in V[G] (in order) do
for each v in Adj[u] doRelax(u, v, w)
odod
Shortest Paths in DAGs
Topologically sort vertices in G;Initialize all dist(.) values to INFdist(s) = 0for each v ∈ V , in linearized order do
dist(v) = min(u,v) E∈ { dist(u) + w(u,v) }
Topologically sort vertices in G;Initialize all dist(.) values to INFdist(s) = 0for each v ∈ V , in linearized order do
dist(v) = min(u,v) E∈ { dist(u) + w(u,v) }
Example
0 r s t u v w
5 2 7 –1 –2
6 1
32
4
Example
0 r s t u v w
5 2 7 –1 –2
6 1
32
4
Example
0 2 6 r s t u v w
5 2 7 –1 –2
6 1
32
4
Example
0 2 6 6 4
r s t u v w5 2 7 –1 –2
6 1
32
4
dist[u]=min{dist[s]+6, dist[t]+7}
Example
0 2 6 5 4
r s t u v w5 2 7 –1 –2
6 1
32
4
Example
0 2 6 5 3
r s t u v w5 2 7 –1 –2
6 1
32
4
Example
0 2 6 5 3
r s t u v w5 2 7 –1 –2
6 1
32
4
Dijkstra’s AlgorithmAssumes no negative-weight edges.
Maintains a set S of vertices whose SP from s has been determined.
Repeatedly selects u in V–S with minimum SP estimate (greedy choice).
Store V–S in priority queue Q.Initialize(G, s);S := ;Q := V[G];while Q do
u := Extract-Min(Q);S := S {u};for each v Adj[u] do
Relax(u, v, w)od
od
Initialize(G, s);S := ;Q := V[G];while Q do
u := Extract-Min(Q);S := S {u};for each v Adj[u] do
Relax(u, v, w)od
od
memset(v,0,sizeof(v));memset(f,-1,sizeof(f));for(int i=0;i<n;i++) d[i] = INF;d[0] = 0;for(int i=0;i<n;i++){ int x, m = INF; for(int y=0;y<n;y++) if(!v[y] && d[y]<=m) m = d[x=y]; v[x] = 1; for(int y=0;y<n;y++) if(d[y]<d[x]+w[x][y]) { d[y]=d[x]+w[x][y]; f[y]=x; }}
v1 v2
v6 v7
v3 v4 v5
2
4
2
1 3 10
2
58 4 6
1
0v1
d f
v2
v3
v4
v5
v6
v7
0
0
0
0
0
0
0
2 v1
1 v1
3 v4
3 v4
9 v4
5 v4
8 v36 v7
Dijkstra Example
Example
0
s
u v
x y
10
1
9
2
4 6
5
2 3
7
Example
0
5
10
s
u v
x y
10
1
9
2
4 6
5
2 3
7
Example
0
75
148
s
u v
x y
10
1
9
2
4 6
5
2 3
7
Example
0
75
138
s
u v
x y
10
1
9
2
4 6
5
2 3
7
Example
0
75
98
s
u v
x y
10
1
9
2
4 6
5
2 3
7
Example
0
75
98
s
u v
x y
10
1
9
2
4 6
5
2 3
7
CorrectnessTheorem 24.6: Upon termination, d[u] = δ(s, u) for all u in V(assuming non-negative weights).
Theorem 24.6: Upon termination, d[u] = δ(s, u) for all u in V(assuming non-negative weights).
Proof:
By Lemma 24.11, once d[u] = δ(s, u) holds, it continues to hold.
We prove: For each u in V, d[u] = (s, u) when u is inserted in S.
Suppose not. Let u be the first vertex such that d[u] (s, u) wheninserted in S.
Note that d[s] = (s, s) = 0 when s is inserted, so u s.
S just before u is inserted (in fact, s S).
Proof (Continued)Note that there exists a path from s to u, for otherwise d[u] = (s, u) = by Corollary 24.12.
there exists a SP from s to u. SP looks like this:
x
s
y
u
S
p1
p2
Proof (Continued)Claim: d[y] = (s, y) when u is inserted into S.
We had d[x] = (s, x) when x was inserted into S.
Edge (x, y) was relaxed at that time.
By Lemma 24.14, this implies the claim.
Now, we have: d[y] = (s, y) , by Claim. (s, u) , nonnegative edge weights. d[u] , by Lemma 24.11.
Because u was added to S before y, d[u] d[y].
Thus, d[y] = (s, y) = (s, u) = d[u].
Contradiction.
Complexity
Running time is
O(V2) using linear array for priority queue.
O((V + E) lg V) using binary heap.
O(V lg V + E) using Fibonacci heap.
(See Introduction to Algorithms.)
All-Pairs Shortest Path Notice that finding the shortest path between a
pair of vertices (s, t) in worst case requires first finding the shortest path from s to all other vertices in the graph.
Many applications, such as finding the center or diameter of a graph, require finding the shortest path between all pairs of vertices.
We can run Dijkstra’s algorithm n times (once from each possible start vertex) to solve all-pairs shortest path problem in O(n3). Can we do better?
All-Pairs Shortest Path The Floyd-Warshall algorithm starts by
numbering the vertices of the graph from 1 to n. Define W[i,j]k to be the length of the shortest path from i to j using only vertices numbered from 1,2,…,k as possible intermediate vertices.
When k=0, we are allowed no intermediate vertices, so the only allowed paths are the original edges. Thus the initial all-pairs shortest-path matrix consists of the initial adjacency matrix.
All-Pairs Shortest Path We will perform n iterations, where the kth
iteration allows only the first k vertices as possible intermediate steps on the path between each pair of vertices x and y.
At each iteration, we allow a richer set of possible shortest path by adding a new vertex as a possible intermediary. Allowing the kth vertex as a stop helps only if there is a short path that goes through k, sow[i,j]k =
min(w[i,j]k-1 , w[i,k]k-1 + w[k,j]k-1 )
86
Floyd-Warshall Algorithm
for (i =1; i<=n; i++)for (j =1; j<=n; j++)
d[i][i] = (i==j ? 0 : INF);for (k =1; k<=n; k++)for (i =1; i<=n; i++)for (j =1; j<=n; j++) { if (d[i][j] < d[i][k] + d[k][j]) d[i][j]=d[i][k] + d[k][j];}
87
例题 Sicily 1031 Campus
每对顶点间的最短路径, floyed-warshall 算法 题目的点是用字符串给出的,可用一个 map
把点转成数字:int tot = 0;std::map<string, int> places;if (places.find(s) == places.end()) places[s] = tot++;v = places[s];
例题 电话圈( Calling Circles, ACM/ICPC World Finals 1996, UVa247) 如果两个人互相打电话(直接或间接),则说他们在同一
个电话圈。例如, a 打给 b, b 打给 c, c 打给 d, d 打给 a, 则这 4 个人在同一个圈里;如果 e 打给 f 但 f 不打给 e, 则不能推出 e 和 f 在同一个电话圈里。输入 n(n<=25) 个人的 m 次电话,找出所有电话圈。人名包含字母,不超过25 个字符,且不重复。
分析:首先用 floyd 求出传递闭包,即 g[i][j] 表示 i 是否直接或者间接给 j 打过电话,则当且仅当 g[i][j] = g[j][i] = 1 时,二者出于同一个电话圈。构造一个新图,在“在一个电话圈里”的两个人之间连一条边,然后依次输出各个连通分量的所有人即可。