Greedy Algorithms
A greedy algorithm arrives at a solution by making a sequence of choices, each of which simply looks the best at the moment. The hope is that locally-optimal choices will lead to a globally-optimal solution.
Making Change
def MakingChange(x):Coins = {5, 10, 25, 100, 200}Sum = 0while Sum != x:Let c in Coins be the largest denomination such that Sum + c <= xif there is no such denomination:return "No Solution"Add c to the change that will be returnedSum = Sum + c
The 0, 1 - Knapsack Problem
Find a greedy algorithm to solve the following problem.
input:
- objects such that object (1 \leq i \leq n) has a positive value and a positive weight .
- A maximum weight .
output: A vector such that
- The total value is maximized.
- The total weight is not too heavy: .
Lemma
If the objects are selected in order of decreasing , then the greedy choice finds an optimal solution.
Algorithm
- Compute all the
- Sort the objects in decreasing order of (use MergeSort)
- Build the solution by applying the greedy choice with respect to decreasing order of .
Total time:
Minimum Spanning Tree
We are given edge that is undirected and connected. Each edge has a weight .
We want a compute a subgraph such that:
- The vertex set of ,
- is connected,
- and is minimum, where
- = sum of weights of edges in .
is called a Minimum Spanning Tree of G (MST of G).
Lemma
Let be an undirected and connected graph, where each edge has a weight .
Split into and . Let be a shortest edge connecting and . then there is an MST of that contains .
From the previous lemma, any algorithm that follows this greedy scheme is guaranteed to work:
- X = {}
- Repeat until
- Pick a set such that has no edge between and .
- Let be a minimum-weight edge between and .
Union-Find Data Structure
Before presenting a first algorithm to compute an MST, we first open a parenthesis and study a data structure called Union-find.
Given sets, each of size one, process a sequence of operation, where each operation is one of:
def union (A,B,C):Set C = A U BA = {}B = {}def find (x):Return the name of the set that contains x
The sequence consists of Union operations, Find operations. This can be done in any arbitrary order.
We store each set in a list:
- the list has a pointer to the head and a pointer to the tail
- the first node stores the name of the set and the size of the set
- each other node stores one element of the set
- each node stores two pointers:
- next() the next node in the list
- back() first node in the list
For the Union Function:
- if size of set is larger than , append to . Otherwise append to .
- running time
For the Find function:
- follow the back pointed from the node storing to the head of the list and return the name stored at the head.
Total running time:
- Union operations = $O (n \log{n})
- Any sequence of Union operations and Find operations takes
Kruskal Algorithm
- Approach: Maintain a forest. In each step, add an edge of minimum weight that does not create a cycle.
- Start: At the beginning, each vertex is a (trivial) tree.
- One Iteration: Combine two trees using an edge of minimum weight
# Input: G = (V,E), where V = {x1, x2, ..., xn} and m = |E|# Output: A minimum spanning tree of Gdef Kruskal(G):Sort the edges of E by weight using Merge Sortfor i in range(n):V[i] = x[i]T = {}for k in range(m):Let u[k] and v[k] be the vertices of e[k]Let i be the index such that u[k] is in V[i]Let j be the index such that v[k] is in V[j]if (i != j):V[i] = Vi[i] union V[j]V[j] = {}T = T union {{u[k], v[k]}}return T
Running time
- Sorting:
- First loop: time
- Second for loop:
- Store in a linked list Total time to maintain this list: time
- Store the sets using the Union-Find data structure
- In this second For-Loop, we do
- Find operations
- Union operations
- So in total for the second for loop:
- Total running time is
Prim Algorithm
Start:
- is a set consisting of one (arbitrary) vertex of
- is an empty set of edges.
One Iteration:
- Take an edge of minimum weight such that and
- Add the edge to
- Move from to
Repeat until (i.e. )!
# Input: G = (V,E)# Output: A minimum spanning tree of Gdef Prim(G):Let r in V be an arbitrary vertex.A = {r}T = {}while A != V:# Q = V\Afind an edge {u, v} in E of min weight such that u in A and v in QA = A union {v}T = T union {{u,v}}
Finding the edge takes time, so total running time is
To improve running time, we can maintain extra information.
For each vertex , minweight: minimum weight of any edge between y and a vertex of . closest: vertex for which . Observe that: a shortest edge connecting and has weight .
Algorithm
# Input: G = (V , E)# Output: A minimum spanning tree of GLet r ∈ V be an arbitrary vertexA = {r}T = { }for each vertex y != r:minweight(y) = infinityclosest(y) = nilfor each edge {r, y}:minweight(y) = wt(r, y)closest(y) = rQ = V \ {r}k = 1 # Stores the size of Awhile k != n:Let v be the vertex of Q for which minweight(v) is minimumu = closest(v)A = A ∪ {v}Q = Q \ {v}T = T ∪ {{u, v}}k = k + 1for each edge {v, y}:if y ∈ Q and wt(v, y) < minweight(y):minweight(y) = wt(v, y)closest(y) = vreturn T
- Store the vertices of in a min-heap.
- For each vertex , the key of is minweight(v).
- Store in a list.
- With each vertex of , store one bit indicating whether the vertex
- belongs to or to .
Running time:
- Up to the while loop: time (this includes the time to build the heap).
- One iteration of the while-loop:
- extract min: time
- At most many decrease key operations: time
- Total time for the while-loop: $O (m \log{n})