Make the best or greedy choice at any given step.
Solves an optimization problem piece-by-piece by making choices that are:
Why? — Approximations can be wildly faster than precise ones.
Applies to Problems with:
Optimal Solutions:
Approximations:
Spanning Tree: A spanning tree of G is a connected acyclic subgraph that has all of G’s vertices.
Minimum Spanning Tree: A weighted version of the above.
Any efficient network design!
Grow a MST by repeatedly adding the least-cost edge that connects a vertex in a the existing tree to a vertex not in the existing subtree.
ALGORITHM Prim(G)// Prim's algorithm for constructing a MST// Input: A weighted connected graph G = <V, E>// Output: E_T, the set of edges composing a minimum spanning tree of GV_T \leftarrow {v_0} // Start with an arbitrary vertexE_T \leftarrow empty setfor i \leftarrow 1 to |V| \text{$-$} 1 dofind minimum-weight edge e* = (v*, u*) among all edges (v, u)such that v is in V_T and u is in V \text{$-$} V_TV_T \leftarrow V_T union {u*}E_T \leftarrow E_T union {e*}return E_T
Analysis — Time complexity is O(|E| \log |V|) if implemented with a min-heap priority queue.
Grow a MST by repeatedly adding the last-cost edge that doesn’t introduce a cycle among the edge included so far.
Note — Key Question: How do you determine if its acyclic still?
If the two nodes being connected:
- belong to the same connected component, it’ll generate a cycle!
- don’t belong to the same connected component, it’s safe!
Aside — Union-Find Problem:
This is a requirement for Kruskal’s to find cycles efficiently. We use a disjoint-set data structure that supports MakeSet, Find, and Union.
Example: Union-Find Execution
Let S = \{ 1,2,3,4,5,6 \}
Applying MakeSet() six times, we initialize the structure of a selection of 6 singletons. When we add an edge connecting 1 and 2, we Union(1,2). To check if an edge 2-3 creates a cycle, we check if Find(2) == Find(3). If not, we Union them.
ALGORITHM Kruskal(G)// Kruskal's algorithm for constructing a MST// Input: A weighted connected graph G = <V, E>// Output: E_T, the set of edges composing a minimum spanning tree of GSort E in nondecreasing order of edge weightsE_T \leftarrow empty setEcounter \leftarrow 0; k \leftarrow 0Initialize |V| disjoint subsets for each vertexwhile Ecounter \lt |V| \text{$-$} 1 dok \leftarrow k \text{$+$} 1e \leftarrow E[k] (which connects u and v)if Find(u) \ne Find(v)E_T \leftarrow E_T union {e}Union(u, v)Ecounter \leftarrow Ecounter \text{$+$} 1return E_T
Analysis — Sorting is the main thing O(|E| \log |E|). MakeSet O(|V|), Find and Union operations with path compression are nearly constant time. Thus, total time is O(|E| \log |E|).
Note — Remember: Do not mismatch this problem with a problem in the last chapter (Floyd’s algortihm). This problem is about one node’s relationship to everyr other node! Floyd’s was about every node!
Problem: Given a weighted connected graph G, find shortest paths for soruce vertex s to each of the other vertices.
Actually pretty similar to Prim’s MST.
Among vertices not already in the tree, finds vertex u with the smallest sum.
d_v + w(v,u)
where:
ALGORITHM Dijkstra(G, s)// Dijkstra's algorithm for single-source shortest paths// Input: A weighted connected graph G and starting vertex s// Output: Shortest distance from s to every other vertexInitialize priority queue Q with all verticesfor each v in V do d[v] \leftarrow infinityd[s] \leftarrow 0while Q is not empty dou \leftarrow ExtractMin(Q)for each neighbor v of u doif d[u] \text{$+$} w(u, v) \lt d[v]d[v] \leftarrow d[u] \text{$+$} w(u, v)DecreaseKey(Q, v, d[v])
Analysis — Efficiency: O(|V|^2) for graphs represented by weight matrix and array implementation of priority queue. O(|E| \log |V|) for graphs represented by adj. lists and min-heap. Space complexity is O(|V|).
Aside — A* is an extended version of this.
| Tree Vertices | Remaining Vertices |
|---|---|
| a(-,0) | b(a,3), c(-,infinity), d(a,7), e(-,infinity) |
| b(a,3) | c(b,3+4), d(b,3+2), e(-,infinity) |
| d(b,5) | c(b,7), e(d, 5+4) |
| c(b,7) | e(d, 9) |
| Tree Vertices | Remaining Vertices |
|---|---|
| BWI(-,0) | JFK(BWI, 184), MIA(BWI, 946), ORD(BWI, 621) |
| JFK(BWI, 184) | ORD(JFK, 740 + 184), BOS(JFK, 187 + 184), PVD(JFK, 144 + 184), MIA(JFK, 946 + 184) |
| ORD(BWI, 621) | DFW(ORD, 1542), MIA(BWI, 946), SFO(ORD, 2462) |
| MIA(BWI, 946) | LAX(MIA, 3289), LAX(DFW, 2777), LAX(SFO, 2799) |
Basically we find “what is the shortest path to this node?” and then build the shortest path by gradually extending and building paths out of these optimal little legos.
Note — Aside Notes:
- Doesn’t work for negative weights
- Works on directed and undirected.
- Don’t get it twisted with Prim’s nor Floyd’s! Prim’s doesn’t consider path accumulation, it just looks at raw edge weight.
Coding: Assignment of bit strings to alphabet characters
Codewords: Bit strings assigned for characters of alphebet.
Two Types of Codes:
Problem: If the frequencies of the character occurence are know (e.g., Standard American English), what’s the best binary prefix-free code33. No codeword is a prefix of another codeword. This ensures that the encoded string can be uniquely and instantaneously decoded from left to right.?
It’s an optimal prefix code generated by creating a binary tree using the frequency of the character as a weight. We repeatedly merge the two lowest-frequency nodes into a new parent node whose frequency is their sum, continuing until we have a single root. Left edges get ‘0’, right edges get ‘1’.
ALGORITHM Huffman(C)// Builds a Huffman tree// Input: A set C of n characters and their frequencies// Output: A Huffman tree for the charactersInitialize a priority queue Q with all characters ordered by frequencyfor i \leftarrow 1 to n \text{$-$} 1 doAllocate a new node zz.left \leftarrow x \leftarrow ExtractMin(Q)z.right \leftarrow y \leftarrow ExtractMin(Q)z.freq \leftarrow x.freq \text{$+$} y.freqInsert(Q, z)return ExtractMin(Q) // root of the tree
Analysis — Time complexity is O(n \log n) due to priority queue operations. Space complexity is O(n) to store the tree.
Eerie eyes seen near lake
| Char | Freq |
|---|---|
| E | 8 |
| R | 2 |
| I | 1 |
| Y | 1 |
| S | 2 |
| N | 2 |
| A | 1 |
| L | 1 |
| K | 1 |
| . | 1 |
Okay so the encoded file is pretty cool. We get like 25—30% savings.