CS6045: Advanced Algorithms Graph Algorithms Graph Representation • A graph G = (V, E) – V = set of vertices – E = set of edges = subset of V V – Thus |E| = O(|V|2) Graph Variations • Variations: – A connected graph has a path from every vertex to every other – In an undirected graph: • Edge (u,v) = edge (v,u) • No self-loops – In a directed graph: • Edge (u,v) goes from vertex u to vertex v, notated uv Graph Variations • More variations: – A weighted graph associates weights with either the edges or the vertices • e.g., a road map: edges might be weighted with distance – A hypergraph allows multiple edges between the same vertices • e.g., the call graph in a program (a function can get called from multiple points in another function) Graphs • We will typically express running times in terms of |E| and |V| – If |E| |V|2 the graph is dense – If |E| |V| the graph is sparse • If you know you are dealing with dense or sparse graphs, different data structures may make sense Representing Graphs • Assume V = {1, 2, …, n} • An adjacency matrix represents the graph as a n x n matrix A: if edge (i, j) E if edge (i, j) E – A[i, j] = 1, = 0, – A[i, j] = weight on the edge, if edge (i, j) E = 0, if edge (i, j) E Graphs: Adjacency Matrix • Example: A 1 d b 4 c 3 2 3 1 a 2 1 2 3 4 ?? 4 Graphs: Adjacency Matrix • Example: 1 a d 2 b 4 c 3 A 1 2 3 4 1 0 1 1 0 2 0 0 1 0 3 0 0 0 0 4 0 0 1 0 • How much storage does the adjacency matrix require? • A: O(V2) Graphs: Adjacency Matrix • The adjacency matrix is a dense representation – Usually too much storage for large graphs – But can be very efficient for small graphs • Most large interesting graphs are sparse – e.g., planar graphs, in which no edges cross, have |E| = O(|V|) by Euler’s formula – For this reason the adjacency list is often a more appropriate representation Graphs: Adjacency List • Adjacency list: for each vertex v V, store a list of vertices adjacent to v • Example: For an undirected graph Graphs: Adjacency List • Adjacency list: for each vertex v V, store a list of vertices adjacent to v • Example: For a directed graph Graphs: Adjacency List • How much storage is required? – The degree of a vertex v = # of edges • Directed graphs have in-degree, out-degree – For directed graphs, # of items in adjacency lists is out-degree(v) = |E| takes O(V + E) storage – For undirected graphs, # items in adjacency lists is degree(v) = 2 |E| (handshaking lemma) also O(V + E) storage • So: Adjacency lists take O(V+E) storage Graph Searching • Given: a graph G = (V, E), directed or undirected • Goal: methodically explore every vertex and every edge • Ultimately: build a tree on the graph – Pick a vertex as the root – Choose certain edges to produce a tree – Note: might also build a forest if graph is not connected Breadth-First Search • “Explore” a graph, turning it into a tree – One vertex at a time – Expand frontier of explored vertices across the breadth of the frontier • Builds a tree over the graph – Pick a source vertex to be the root – Find (“discover”) its children, then their children, etc. Breadth-First Search • Again will associate vertex “colors” to guide the algorithm – White vertices have not been discovered • All vertices start out white – Grey vertices are discovered but not fully explored • They may be adjacent to white vertices – Black vertices are discovered and fully explored • They are adjacent only to black and gray vertices • Explore vertices by scanning adjacency list of grey vertices Breadth-First Search BFS(G, s) { initialize vertices V.d = ; s.d = 0; Q = {s}; // Q is a queue; initialize to s while (Q not empty) { u = Dequeue(Q); for each v u->adj { if (v->color == WHITE) v->color = GREY; v->d = u->d + 1; What does v->d represent? v->p = u; What does v->p represent? Enqueue(Q, v); } u->color = BLACK; } } Breadth-First Search: Example r s t u v w x y Breadth-First Search: Example r s t u 0 v w x y Q: s Breadth-First Search: Example r s t u 1 0 1 v w x y Q: w r Breadth-First Search: Example r s t u 1 0 2 1 2 v w x y Q: r t x Breadth-First Search: Example r s t u 1 0 2 2 1 2 v w x y Q: t x v Breadth-First Search: Example r s t u 1 0 2 3 2 1 2 v w x y Q: x v u Breadth-First Search: Example r s t u 1 0 2 3 2 1 2 3 v w x y Q: v u y Breadth-First Search: Example r s t u 1 0 2 3 2 1 2 3 v w x y Q: u y Breadth-First Search: Example r s t u 1 0 2 3 2 1 2 3 v w x y Q: y Breadth-First Search: Example r s t u 1 0 2 3 2 1 2 3 v w x y Q: Ø BFS: The Code Again BFS(G, s) { Touch every vertex: O(V) initialize vertices V.d = ; s.d = 0; Q = {s}; while (Q not empty) { u = Dequeue(Q); u = every vertex, but only once for each v u->adj { if (v->color == WHITE) v = every vertex v->color = GREY; v->d = u->d + 1; that appears in some other vert’s v->p = u; Enqueue(Q, v); adjacency list } What will be the running time? u->color = BLACK; Total running time: O(V+E) } } BFS: The Code Again BFS(G, s) { initialize vertices V.d = ; s.d = 0; Q = {s}; while (Q not empty) { u = Dequeue(Q); for each v u->adj { if (v->color == WHITE) v->color = GREY; v->d = u->d + 1; v->p = u; Enqueue(Q, v); What will be the storage cost } in addition to storing the tree? u->color = BLACK; Total space used: } O(max(degree(v))) = O(E) } Breadth-First Search: Properties • BFS calculates the shortest-path distance to the source node – Shortest-path distance (s,v) = minimum number of edges from s to v, or if v not reachable from s • BFS builds breadth-first tree, in which paths to root represent shortest paths in G – Thus can use BFS to calculate shortest path from one vertex to another in O(V+E) time Depth-First Search • Depth-first search is another strategy for exploring a graph – Explore “deeper” in the graph whenever possible – Edges are explored out of the most recently discovered vertex v that still has unexplored edges – When all of v’s edges have been explored, backtrack to the vertex from which v was discovered Depth-First Search • Vertices initially colored white • Then colored gray when discovered • Then black when finished Depth-First Search: The Code DFS(G) { for each vertex u G>V { u->color = WHITE; } time = 0; for each vertex u G>V { if (u->color == WHITE) DFS_Visit(u); } } DFS_Visit(u) { u->color = GREY; time = time+1; u->d = time; What does u->d represent? for each v u->Adj[] { if (v->color == WHITE) DFS_Visit(v); } u->color = BLACK; time = time+1; u->f = time;What does u->f represent? } Will all vertices eventually be colored black? What will be the running time? Depth-First Search: The Code DFS(G) { for each vertex u G>V { u->color = WHITE; } time = 0; for each vertex u G>V { if (u->color == WHITE) DFS_Visit(u); } } DFS_Visit(u) { u->color = GREY; time = time+1; u->d = time; for each v u->Adj[] { if (v->color == WHITE) DFS_Visit(v); } u->color = BLACK; time = time+1; u->f = time; } Running time: O(n2) because call DFS_Visit on each vertex, and the loop over Adj[] can run as many as |V| times Depth-First Search: The Code DFS(G) { for each vertex u G>V { u->color = WHITE; } time = 0; for each vertex u G>V { if (u->color == WHITE) DFS_Visit(u); } } DFS_Visit(u) { u->color = GREY; time = time+1; u->d = time; for each v u->Adj[] { if (v->color == WHITE) DFS_Visit(v); } u->color = BLACK; time = time+1; u->f = time; } BUT, there is actually a tighter bound. Running time of DFS = O(V+E) DFS Example source vertex 1 3 2 5 4 6 7 8 DFS Example source vertex d|f 1| | 1 | 2 4 | | | | 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2| 1 | 2 4 | | | | 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2| 1 | 2 4 | | 3| | 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2| 1 | 2 4 | | 3|4 | 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2| 1 | 2 4 | | 3|4 5| 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2| 1 | 2 4 | | 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2|7 1 | 2 4 | | 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2|7 1 8| 2 4 | | 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2|7 1 8| 2 4 | 9| 3|4 5 5|6 6 3 | 7 What do the grey vertices represent? 8 DFS Example source vertex d|f 1| 2|7 1 8| 2 4 | 9|10 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1| 2|7 1 8|11 2 4 | 9|10 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1|12 2|7 1 8|11 2 4 | 9|10 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1|12 2|7 1 8|11 2 4 13| 9|10 3|4 5|6 6 3 5 | 7 8 DFS Example source vertex d|f 1|12 2|7 1 8|11 2 4 13| 9|10 3|4 5|6 6 3 5 14| 7 8 DFS Example source vertex d|f 1|12 2|7 1 8|11 2 4 13| 9|10 3|4 5|6 6 7 3 5 14|15 8 DFS Example source vertex d|f 1|12 2|7 1 8|11 3 13|16 2 4 9|10 3|4 5|6 6 7 5 14|15 8 DFS Properties • Parenthesis Theorem – For all u, v, exactly one of the following holds: 1. The intervals [u.d, u.f] and [v.d, v.f] are disjoint, neither of u and v is a descendant of the other 2. The interval [u.d, u.f] is contained entirely within the interval [v.d, v.f], u is a descendant of v in a depth-first tree 3. The interval [u.d, u.f] is contained entirely within the interval [v.d, v.f], v is a ancestor of u in a depth-first tree • Corollary – v is a proper descendant of u if and only if u.d<v.d<v.f<u.f DFS: Kinds of edges • DFS introduces an important distinction among edges in the original graph: – Tree edge: encounter new (white) vertex • The tree edges form a spanning forest • Can tree edges form cycles? Why or why not? DFS Example source vertex d|f 1|12 2|7 1 8|11 3 13|16 2 4 9|10 3|4 5|6 6 Tree edges 7 5 14|15 8 DFS: Kinds of edges • DFS introduces an important distinction among edges in the original graph: – Tree edge: encounter new (white) vertex – Back edge: from descendent to ancestor • Encounter a grey vertex (grey to grey) DFS Example source vertex d|f 1|12 2|7 1 8|11 3 13|16 2 4 9|10 3|4 5|6 6 Tree edges Back edges 7 5 14|15 8 DFS: Kinds of edges • DFS introduces an important distinction among edges in the original graph: – Tree edge: encounter new (white) vertex – Back edge: from descendent to ancestor – Forward edge: from ancestor to descendent • Not a tree edge • From grey node to black node DFS Example source vertex d|f 1|12 2|7 1 8|11 3 13|16 2 4 9|10 3|4 5 5|6 6 7 Tree edges Back edges Forward edges 14|15 8 DFS: Kinds of edges • DFS introduces an important distinction among edges in the original graph: – – – – Tree edge: encounter new (white) vertex Back edge: from descendent to ancestor Forward edge: from ancestor to descendent Cross edge: between a tree or subtrees • Any other edges • From a grey node to a black node DFS Example source vertex d|f 1|12 2|7 1 8|11 3 13|16 2 4 9|10 3|4 5|6 6 7 5 14|15 8 Tree edges Back edges Forward edges Cross edges DFS: Kinds of edges • DFS introduces an important distinction among edges in the original graph: – – – – Tree edge: encounter new (white) vertex Back edge: from descendent to ancestor Forward edge: from ancestor to descendent Cross edge: between a tree or subtrees • Note: If G is undirected, a DFS produces only tree and back edges. No forward or cross edges. DFS And Graph Cycles • Theorem: An undirected graph is acyclic iff a DFS yields no back edges – If acyclic, no back edges (because a back edge implies a cycle – If no back edges, acyclic • No back edges implies only tree edges • Only tree edges implies we have a tree or a forest • Which by definition is acyclic • Thus, can run DFS to find whether a graph has a cycle Directed Acyclic Graphs • A directed acyclic graph or DAG is a directed graph with no directed cycles: Topological Sort • Topological sort of a DAG: – Linear ordering of all vertices in graph G such that vertex u appears somewhere before vertex v if edge (u, v) G • Real-world example: getting dressed Getting Dressed Underwear Socks Watch Pants Shoes Shirt Belt Tie Jacket Getting Dressed Underwear Socks Watch Pants Shoes Shirt Belt Tie Jacket Socks Underwear Pants Shoes Watch Shirt Belt Tie Jacket Topological Sort Algorithm Topological-Sort() { Run DFS to compute finish time v.f for all v V Output vertices in order of decreasing finishing times } • Time: O(V+E) Getting Dressed 11/16 Underwear Socks 17/18 Watch 12/15 6/7 Pants Shoes Shirt 1/8 Tie 2/5 Jacket 3/4 9/10 13/14 Belt Socks Underwear 17/18 11/16 Pants Shoes Watch Shirt Belt Tie Jacket 12/15 13/14 9/10 1/8 6/7 2/5 3/4 Minimum Spanning Tree • Problem: given a connected, undirected, weighted graph, find a spanning tree (T) using edges that minimize the total weight, i.e., minimize (𝑢,𝑣)∈𝑇 𝑤(𝑢, 𝑣) Minimum Spanning Tree • Which edges form the minimum spanning tree (MST) of the below graph? A 6 4 5 H B 14 C 15 D 2 10 G E 3 9 F 8 Minimum Spanning Tree • Answer: A 6 4 5 H B 14 C 15 D 2 10 G E 3 9 F 8 Minimum Spanning Tree • MSTs satisfy the optimal substructure property: an optimal tree is composed of optimal subtrees – Let T be an MST of G with an edge (u,v) in the middle – Removing (u,v) partitions T into two trees T1 and T2 – Claim: T1 is an MST of G1 = (V1,E1), and T2 is an MST of G2 = (V2,E2) – Proof: w(T) = w(u,v) + w(T1) + w(T2) Minimum Spanning Tree • MSTs satisfy the greedy-choice property: – Let T be MST of G, and let A T be subtree of T – Let (u,v) be min-weight edge connecting A to the rest of the Graph (V - A) – Then (u,v) T Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 9 5 for each u Q key[u] = ; 14 2 10 key[r] = 0; 15 p[r] = NULL; 3 while (Q not empty) 8 u = ExtractMin(Q); Run on example graph for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 for each u Q key[u] = ; 14 2 10 key[r] = 0; p[r] = NULL; 3 while (Q not empty) 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 9 5 for each u Q key[u] = ; 14 2 10 key[r] = 0; 15 r 0 p[r] = NULL; 3 while (Q not empty) 8 u = ExtractMin(Q); Pick a start vertex r for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 9 5 for each u Q key[u] = ; 14 2 10 key[r] = 0; 15 u 0 p[r] = NULL; 3 while (Q not empty) 8 u = ExtractMin(Q); Red vertices have been removed from Q for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 9 5 for each u Q key[u] = ; 14 2 10 key[r] = 0; 15 u 0 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); Red arrows indicate parent pointers for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 14 for each u Q key[u] = ; 14 2 10 key[r] = 0; u 0 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 14 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 p[r] = NULL; 3 while (Q not empty) 8 3 u u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 14 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 8 3 u u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 10 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 8 3 u u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 10 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 10 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 10 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 10 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); u 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 6 4 Q = V[G]; 5 10 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); u 9 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 4 6 4 Q = V[G]; 5 10 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); u 9 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 4 6 4 Q = V[G]; 5 5 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); u 9 9 15 15 Prim’s Algorithm u MST-Prim(G, w, r) 4 6 4 Q = V[G]; 5 5 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 4 6 4 Q = V[G]; 5 5 2 u for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 4 6 4 Q = V[G]; 5 5 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); u 9 9 15 15 Prim’s Algorithm MST-Prim(G, w, r) 4 6 4 Q = V[G]; 5 5 2 for each u Q key[u] = ; 14 2 10 key[r] = 0; 0 8 p[r] = NULL; 3 while (Q not empty) 3 8 u = ExtractMin(Q); for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); 9 9 15 15 u Prim’s Algorithm MST-Prim(G, w, r) What is the hidden cost in this code? Q = V[G]; A: DECREASE-KEY operation for each u Q key[u] = ; on the min-heap key[r] = 0; What will be the running time? p[r] = NULL; A: Depends on queue while (Q not empty) u = ExtractMin(Q); binary heap: O(E lg V) for each v Adj[u] if (v Q and w(u,v) < key[v]) p[v] = u; key[v] = w(u,v); Kruskal’s Algorithm Run the algorithm: 2 19 Kruskal() { 14 17 8 25 T = ; for each v V 21 13 MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 5 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 9 14 17 { 8 25 5 T = ; 21 13 1? for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2? 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 9 14 17 { 8 25 5? T = ; 21 13 1 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8? 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 9? 14 17 { 8 25 5 T = ; 21 13 1 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13? for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14? 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17? { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19? Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21? 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25? 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Kruskal’s Algorithm 2 19 Kruskal() 14 17 { 8 25 5 T = ; 21 13 for each v V MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } 9 1 Correctness Of Kruskal’s Algorithm • Sketch of a proof that this algorithm produces an MST for T: – Assume algorithm is wrong: result is not an MST – Then algorithm adds a wrong edge at some point – If it adds a wrong edge, there must be a lower weight edge – But algorithm chooses lowest weight edge at each step. Contradiction Kruskal’s Algorithm What will affect the running time? Kruskal() Sort { O(V) MakeSet() calls T = ; O(E) FindSet() calls for each v V O(V) Union() calls MakeSet(v); sort E by increasing edge weight w for each (u,v) E (in sorted order) if FindSet(u) FindSet(v) T = T U {{u,v}}; Union(FindSet(u), FindSet(v)); } Kruskal’s Algorithm: Running Time • To summarize: – – – – – Sort edges: O(E lg E) O(V) MakeSet()’s O(E) FindSet()’s O(V) Union()’s Overall O(E lg E) Single-Source Shortest Path • Problem: given a weighted directed graph G, find the minimum-weight path from a given source vertex s to another vertex v – “Shortest-path” = minimum weight – Weight of path is sum of edges – Might not be unique Shortest Path Properties • Again, we have optimal substructure: the shortest path consists of shortest subpaths: – Proof: suppose some subpath is not a shortest path • There must then exist a shorter subpath • Could substitute the shorter subpath for a shorter path • But then overall path is not shortest path. Contradiction Shortest Path Properties • Define (u,v) to be the weight of the shortest path from u to v • Shortest paths satisfy the triangle inequality: (u,v) (u,x) + (x,v) x u v This path is no longer than any other path Shortest Path Properties • In graphs with negative weight cycles, some shortest paths will not exist • Shortest path can’t contain cycles <0 Relaxation • A key technique in shortest path algorithms is relaxation – Idea: for all v, maintain upper bound d[v] on (s,v) Relax(u,v,w) { if (d[v] > d[u]+w) then d[v]=d[u]+w; } 2 2 9 6 5 5 Relax 5 2 Relax 7 5 2 6 Bellman-Ford Algorithm BellmanFord() for each v V d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; Initialize d[], which will converge to shortest-path value Relaxation: Make |V|-1 passes, relaxing each edge Test for solution: have we converged yet? i.e., negative cycle? Relax(u,v,w): if (d[v] > d[u]+ w) then d[v]=d[u]+w Bellman-Ford Algorithm BellmanFord() for each v V What will be the running time? A: O(VE) d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; Bellman-Ford Algorithm BellmanFord() for each v V s d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; B A -1 0 3 2 2 1 4 C 5 Relax(u,v,w): if (d[v] > d[u]+w) then d[v]=d[u]+w E -3 D Bellman-Ford Algorithm BellmanFord() for each v V s d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; B -1 -1 A 0 3 1 4 4 C 5 Relax(u,v,w): if (d[v] > d[u]+w) then d[v]=d[u]+w 2 2 E -3 D Bellman-Ford Algorithm BellmanFord() for each v V s d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; B -1 -1 A 0 3 1 4 2 C 5 Relax(u,v,w): if (d[v] > d[u]+w) then d[v]=d[u]+w 2 2 E 1 -3 1 D Bellman-Ford Algorithm BellmanFord() for each v V s d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; B -1 -1 A 0 3 1 4 2 C 5 Relax(u,v,w): if (d[v] > d[u]+w) then d[v]=d[u]+w 2 2 E 1 -3 -2 D Bellman-Ford Algorithm BellmanFord() for each v V s d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; B -1 -1 A 0 3 1 4 2 C 5 Relax(u,v,w): if (d[v] > d[u]+w) then d[v]=d[u]+w 2 2 E 1 -3 -2 D Bellman-Ford Algorithm BellmanFord() for each v V s d[v] = ; d[s] = 0; for i=1 to |V|-1 for each edge (u,v) E Relax(u,v, w(u,v)); for each edge (u,v) E if (d[v] > d[u] + w(u,v)) return “no solution”; B -1 -1 A 0 3 1 4 2 C 5 Relax(u,v,w): if (d[v] > d[u]+w) then d[v]=d[u]+w 2 2 E 1 -3 -2 D Bellman-Ford Algorithm • Note that order in which edges are processed affects how quickly it converges • Correctness: show d[v] = (s,v) after |V|-1 passes DAG Shortest Paths • Problem: finding shortest paths in DAG – Bellman-Ford takes O(VE) time. – How can we do better? – Idea: use topological sort DAG-Shortest-Paths(G,w,s) topologically sort the vertices for each v V d[v] = ; d[s] = 0; for each vertex u, taken in topologically sorted order for each vertex v Adj[u] Relax(u,v,w) DAG Shortest Paths 6 2 0 7 A B 2 0 6 7 2 A B 2 0 7 6 B A 2 2 -1 C B 7 D C 6 0 D -1 6 6 2 A C -1 6 C -1 5 D 1 5 D 1 -2 E 1 -2 E 1 -2 7 E -2 3 E DAG Shortest Paths • Problem: finding shortest paths in DAG – Idea: use topological sort • If were lucky and processes vertices on each shortest path from left to right, would be done in one pass • Every path in a DAG is subsequence of topologically sorted vertex order, so processing verts in that order, we will do each path in forward order (will never relax edges out of vertices before doing all edges into vertices). • Thus: just one pass. • Time: O(V + E) Dijkstra’s Algorithm • If no negative edge weights, Dijkstra’s essentially a weighted version of breadth-first search • Similar to breadth-first search – Grow a tree gradually, advancing from vertices taken from a queue • Also similar to Prim’s algorithm for MST – Use a priority queue keyed on d[v] Dijkstra’s Algorithm B Dijkstra(G) for each v V 2 D A 10 d[v] = ; 4 3 d[s] = 0; S = ; Q = V; 5 1 while (Q ) C u = ExtractMin(Q); S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) Relaxation d[v] = d[u]+w(u,v); Step Dijkstra’s Algorithm B Dijkstra(G) for each v V 2 D s A 10 d[v] = ; 4 3 0 d[s] = 0; S = ; Q = V; 5 1 while (Q ) C u = ExtractMin(Q); S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); Dijkstra’s Algorithm B 10 Dijkstra(G) for each v V 2 D s A 10 d[v] = ; 4 3 0 d[s] = 0; S = ; Q = V; 5 1 5 while (Q ) C u = ExtractMin(Q); S = {A} S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); Dijkstra’s Algorithm B 9 Dijkstra(G) for each v V 2 D s A 10 d[v] = ; 4 3 0 6 d[s] = 0; S = ; Q = V; 5 1 5 while (Q ) C u = ExtractMin(Q); S = {A, C} S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); Dijkstra’s Algorithm B 8 Dijkstra(G) for each v V 2 D s A 10 d[v] = ; 4 3 0 6 d[s] = 0; S = ; Q = V; 5 1 5 while (Q ) C u = ExtractMin(Q); S = {A, C, D} S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); Dijkstra’s Algorithm B 8 Dijkstra(G) for each v V 2 D s A 10 d[v] = ; 4 3 0 6 d[s] = 0; S = ; Q = V; 5 1 5 while (Q ) C u = ExtractMin(Q); S = {A, C, D, B} S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); Dijkstra’s Algorithm B 8 Dijkstra(G) for each v V 2 D s A 10 d[v] = ; 4 3 0 6 d[s] = 0; S = ; Q = V; 5 1 5 while (Q ) C u = ExtractMin(Q); S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); Dijkstra’s Algorithm Dijkstra(G) for each v V How many times is ExtractMin() called? d[v] = ; d[s] = 0; S = ; Q = V; while (Q ) How many times is u = ExtractMin(Q); Relax() called? S = S U {u}; for each v u->Adj[] if (d[v] > d[u]+w(u,v)) d[v] = d[u]+w(u,v); What will be the total running time? A: O(E lg V) using binary heap for Q