Greedy Algorithms 2024 Part 1
Greedy Algorithms 2024 Part 1
19 juin 2024
Outline
▶ sort the object in increasing or decreasing order along some sorting criterion
(the ”greedy criterion”)
▶ according to the sorted order, consider each object individually and add it to
the subset that makes the solution if adding the object produce a subset that
still satisfy the constraints of the problem
Greedy algorithms
At each step, a decision is made to add the object or not in the solution
The problem is paying back an amount n to a customer using the smallest possible
number of coins.
Here is a greedy recursive algorithm. The greedy criterion consists to return change
always using the largest possible coin ≤ n. Coins are sorted in decreasing order of
their value, they are then selected in this order to return change.
Greedy MakingChange(int n)
if (n == 0) return 0 ;
c = the largest coin that is no larger than n ;
return (⌊n/c⌋) + Greedy MakingChange(n − (⌊n/c⌋ × c)) ;
Example of making change
Assume the coin denominations are 25, 10, 5 and 1 cents and we make
change for 97 cents using the above greedy algorithm.
▶ Choose the largest coin that is no larger than n (here 25 cents is
the largest coin no larger than 97 cents)
▶ Give out ⌊n/c⌋ of the c cent coins (⌊97/25⌋ = three quarters)
▶ Make change recursively for n − ⌊n/c⌋c cents (97 − 3 × 25 = 22
cents)
▶ 10 cents is the largest coin no larger than 22 cents, so we hand out
two dimes and make change for 22 − 20 = 2 cents
▶ a penny is the largest coin no larger than 2 cents, so we hand out
two pennies and we’re done !
Altogether we hand out 3 quarters, 2 dimes and 2 pennies, for a total
of 7 coins
Greedy may fail to solve making change optimally
The greedy algorithm always gives out the fewest number of coins in
change with these problem instances where coins are quarters, dimes,
nickels and pennies.
It doesn’t give out the fewest number of coins if the coins are 15 cents,
7 cents, 2 cents and 1 cent.
Object i 1 2 3 4 5
Weight wi 2 3 5 6 4
Value vi 6 1 12 8 7
Greedy 0-1-Knapsack(int W = 11,int n)
int selected objects[n] = {0} ; int w = W ; int objects[n] ; int i, j
Sort objects[n] in decreasing order of the object’s values
objects = [3, 4, 5, 1, 2] after sorting
for (i = 1; i ≤ n, i + +)
j = objects[i]
if (w > wj )
selected objects[i] = j
w = w − wj
i = 1, object = 3, selected objects = [3, 0, 0, 0, 0], w = 6
i = 2, object = 4, selected objects = [3, 4, 0, 0, 0], w = 0
Solution is 20
Greedy criterion is weights
Object i 1 2 3 4 5
Weight wi 2 3 5 6 4
Value vi 6 1 12 8 7
Greedy 0-1-Knapsack(int W = 11,int n)
int selected objects[n] = {0} ; int w = W ; int objects[n] ; int i, j
Sort objects[n] in increasing order of the object’s weights
objects = [1, 2, 5, 3, 4] after sorting
for (i = 1; i ≤ n, i + +)
j = objects[i]
if (w > wj )
selected objects[i] = j
w = w − wj
i = 1, object = 1, selected objects = [1, 0, 0, 0, 0], w = 9
i = 2, object = 2, selected objects = [1, 2, 0, 0, 0], w = 6
i = 3, object = 5, selected objects = [1, 2, 5, 0, 0], w = 2
Solution is 14
Greedy criterion is density
Object i 1 2 3 4 5
Weight wi 2 3 5 6 4
Value vi 6 1 12 8 7
Greedy 0-1-Knapsack(int W = 11,int n)
int selected objects[n] = {0} ; int w = W ; int objects[n] ; int i, j
Sort objects[n] in decreasing order of the object’s density wv [i]
[i]
objects = [1, 3, 5, 4, 2] after sorting
for (i = 1; i ≤ n, i + +)
j = objects[i]
if (w > wj )
selected objects[i] = j
w = w − wj
i = 1, object = 1, selected objects = [1, 0, 0, 0, 0], w = 9
i = 2, object = 3, selected objects = [1, 3, 0, 0, 0], w = 4
i = 3, object = 5, selected objects = [1, 2, 5, 0, 0], w = 0
Solution is 25
Problems where greedy strategies fail
The problem is to maximize the sum of the nodes along a path in the
tree.
Greedy algorithm makes decisions purely on local information
The weight of a spanning tree T is the sum of the weights of its edges.
That is, X
w (T ) = w (u, v ).
(u,v )∈T
As for any optimization problem, there could be more than one optimal
solution, here there are two minimum spanning trees.
4 3 2
9 7 4
3 3
G 5
2
6
4 1
3 2 4 3 2
T1 3 3 T2
3 3
2 2
4 1 1
Optimal substructure for MST
Claim :
T1 is an MST of G1 = (V1 , E1 ), and T2 is an MST of G2 = (V2 , E2 )
Assume (u, v ) = (b, e). After removing (b, e) from the MST we have :
1. T1 = {(e, d), (d, g )} and the graph span by the nodes in T1 is
G1 = {(e, d), (d, g ), (e, g )}
2. T2 = {(a, b), (b, c), (a, f )} and the graph span by the nodes in T2
is G2 = {(a, b), (b, c), (a, f ), (f , c), (f , b)}
The MST satisfies the greedy choice property if there exists a sequence of edges selected
greedily which results into a MST.
It is easy to find this sequence. Select first an edge with minimum cost in the graph, here
(d, e). This is the first edge in the MST.
Look locally how the MST can be expanded. There are 6 edges adjacent either to d or e.
Select the one with minimum cost (b, e). There are two edges in the MST.
Make a local choice again by selecting the edge that is adjacent to the current partial MST
and has minimum cost, the edge (b, c).
Proof by induction :
Induction hypothesis : Let T be a MST for a graph G , and A be a subset of edges
in T . In the graph above, assume A = {(a, b), (b, c), (a, f )}
Let C be a cut of G which does not include any edge of A. For the example above,
a cut is {(a, d), (b, d), (b, e), (c, e)}
Induction step : Add to A the edge with minimum cost in the cut, i.e. edge (b, e).
After adding (b, e), A is still part of the MST T for G
This shows that a MST can be constructed by extending the partial MST with a
greedy choice on the length of the edges
Greedy choice property for MST : proof by induction
The MST satisfies the greedy choice property. Starting from the base case.
Let A = ∅ initially. Select edge (b, c) to enter A, A = {(b, c)}. The cut is
C1 = {(c, f ), (b, f ), (a, b), (b, d), (b, e), (c, e)}
The shortest edge in C1 is (a, b), A = A ∪ (a, b) = {(b, c), (a, b)}. The new cut
C2 = {(a, f ), (a, d), (c, f ), (b, f ), (b, d), (b, e), (c, e)}
A = A ∪ (a, f ) = {(b, c), (a, b), (a, f )} given (a, f ) is the shortest edge in the cut
C2 . The new cut C3 = {(a, d), (b, d), (b, e), (c, e)}
etc.
Greedy choice property for MST : proof by contradiction
6 10
B D G
1 7 15
5 9 11 14
A E I
4
8
2 13
C F H
3 12
Theorem :
The minimum spanning tree of G contains every ev
Greedy choice property for MST : proof by contradiction
Proof :
Suppose on the contrary that MST of G does not contain some edge
ev = (u, v ).
Proof :
By our choice of ev , the weight of (u, v ) must be less than the weight
of (v , w ) in T
If we delete (v , w ) and include ev , we obtain a new spanning tree
cheaper than T , a contradiction
Constructing an MST
Both of these algorithms use the same basic ideas, but in a slightly
different fashion.
Kruskal’s Algorithm
Initially makes each node of the graph as a tree with a single node, i.e. a
forest of trees
Then greedily select the shortest edge not making a cycle to be part of the
MST
This edge merge two trees into a single one
Algorithm Kruskal(G )
input : Graph G = (V , E ) ;
output : A minimum spanning tree T ;
Sort E by increasing length ;
n = |V | ;
T = ∅;
For each v ∈ V MakeSet(v)
for i = 1 to |E | do /* Greedy loop */
{u, v } = shortest edge not yet considered ;
if (FindSet(u) ̸= FindSet(v)) then
Union(FindSet(u),
S FindSet(v))
T = T {u, v } ;
return T
Kruskal’s Algorithm Example
for i = 1 to |E | do /* Greedy loop */
{u, v } = shortest edge not yet considered ;
if (FindSet(u) ̸= FindSet(v)) then
Union(FindSet(u),
S FindSet(v))
T = T {u, v } ;
return T
A 5 4 C A 5 4 C
B 1 B 1
4 2 4 2
D
6 E D
6 E
12 2 12 2
9 7 3 8 9 7 3 8
E F G E F G
11 1 11 1
A 5 4 C A 5 4 C
B 1 B 1
4 2 4 2
D 6 E D 6 E
12 2 12 2
9 7 3 8 9 7 3 8
E F G E F G
11 1 11 1
for i = 1 to |E | do /* Greedy loop */
{u, v } = shortest edge not yet considered ;
if (FindSet(u) ̸= FindSet(v)) then
Union(FindSet(u),
S FindSet(v))
T = T {u, v } ;
return T
A 5 4 C A 5 4 C
B 1 B 1
4 2 4 2
D
6 E D
6 E
12 2 12 2
9 7 3 8 9 7 3 8
E F G E F G
11 1 11 1
A 5 4 C
A 5 4 C 4
B 1
B 1 2
4 2 6
6 2 D E
2 D E 12
12 9 7 3 8
9 7 3 8 E F G
E F G 11 1
11 1
for i = 1 to |E | do /* Greedy loop */
{u, v } = shortest edge not yet considered ;
if (FindSet(u) ̸= FindSet(v)) then
Union(FindSet(u),
S FindSet(v))
T = T {u, v } ;
return T
5 4 A 5 4 C
A C B 1
4
B 1 4 2
2 6
D
6 E 12 2 D E
12 2
9 8 9 7 3 8
7 3
E F G
E F G 1
11 1 11
A 5 4 C A 5 4 C
B 1 B 1
4 2 4 2
D
6 E D
6 E
12 2 12 2
9 7 3 8 9 7 3 8
E F G E F G
11 1 11 1
for i = 1 to |E | do /* Greedy loop */
{u, v } = shortest edge not yet considered ;
if (FindSet(u) ̸= FindSet(v)) then
Union(FindSet(u),
S FindSet(v))
T = T {u, v } ;
return T
A 5 4 C A 5 4 C
B 1 B 1
4 2 4 2
D
6 E D
6 E
12 2 12 2
9 7 3 8 9 7 3 8
E F G E F G
11 1 11 1
A 5 4 C 4
B 1
4 2 2 1
6 4
2 D E
12 2
9 7 3 8 9
E F G
11 1 1
Kruskal’s Algorithm : time complexity analysis
Algorithm Kruskal(G )
input : Graph G = (V , E ) ; ▶ Sort edges : O(E log E )
output : A minimum spanning tree T ; ▶ O(n) MakeSet()’s
Sort E by increasing length ; ▶ Aggregate analysis of the second ”for”
n = |V | ; loop yields a cost O(n log n) for the
T = ∅; union operations and 2E FindSet, thus
for each v ∈ V MakeSet(v) O(E + n log n)
for i = 1 to |E | do ▶ If |E | ≈ n2 , in O(E + n log n), E is the
shortest {u, v } not yet considered ; dominant term.
if (FindSet(u) ̸= FindSet(v)) then ▶ However edge sorting cost O(E log E ),
Union(FindSet(u), FindSet(v)) this is the most costly operation of
S Kruskal’s algorithm, O(E log E ) is the
T = T {u, v } ;
asymptotic running time of this algo.
return T
Exercises on Kruskal’s algorithm
Consider the non-oriented weighted graph G below represented using
an adjacency matrix
a b c d e f g h i j k l m
a 1 6 2
b 1 2 3
c 4
d 1 5 3 1
e 1 3 2
f 2
g 4
h 3 1
i 2
j 1
k 1
l 2
m
1
6 5
1
2 5 5 4
3 3 2
6 4
5 6
6
Prim’s Algorithm
1. Prim selects arbitrary a node A of the graph to be the root of the MST
T
2. Then selects the shortest edge adjacent to A to be the first edge of T
3. Prim grows the MST T by selecting the shortest edge adjacent to a
node of T , not yet in T and not forming a cycle
Prim MST(G , r )
∀u∈G
key [u] = Max Int ;
key [r ] = 0 ;
p[r ] = NIL ;
Q = MinPriorityQueue(V )
while (Q ̸= ∅)
u = ExtractMin(Q) ;
for each v adjacent to u
if ((v ∈ Q) & (w (u, v ) < key [v ]))
p[v ] = u ;
key [v ] = w (u, v ) ;
a 5 c 4 v a b c d e f g h
f 1
4 2
6 k 0 oo oo oo oo oo oo oo
while (Q ̸= ∅) 12 2 e h
p nil ? ? ? ? ? ? ?
9 7 3 8
u = ExtractMin(Q) ; b d g
11 1 Q=[a,b,c,d,e,f,g,h]
for each v adjacent to u
5 4
if ((v ∈ Q) a
4
c
2
f 1 v a b c d e f g h
6 k 0 12 5 4 oo oo oo oo
& (w (u, v ) < key [v ])) 12 2 e h
p nil a a
9 3 8 a ? ? ? ?
7
p[v ] = u ; b d g
11 1 Q=[d,c,b,e,f,g,h]
key [v ] = w (u, v ) ;
a 5 c 4 v a b c d e f g h
f 1
4 2
e 6 k 0 11 2 4 7 oo 1 oo
12 2 h
9 8 p nil d d a d ? d ?
7 3
b d g
11 1 Q=[g,c,e,b,f,h]
a 5 c 4 v a b c d e f g h
f 1
4 2
6 k 0 11 2 4 3 8 1 oo
12 2 e h
9 8 p nil d d a g g d ?
7 3
b d g
11 1 Q=[c,e,f,b,h]
a 5 c 4 v a b c d e f g h
f 1
4 2
6 k 0 9 2 4 2 4 1 oo
while (Q ̸= ∅) 12
9
2 e h
p nil c d a c c d ?
7 3 8
u = ExtractMin(Q) ; b d g
11 1 Q=[e,f,b,h]
for each v adjacent to u
5 4
if ((v ∈ Q) a
4
c
2
f 1 v a b c d e f g h
6 k 0 9 2 4 2 4 1 6
& (w (u, v ) < key [v ])) 12 2 e h
p nil c
9 3 8 d a c c d e
p[v ] = u ; 7
b d g
11 1 Q=[f,h,b]
key [v ] = w (u, v ) ;
a 5 c 4 v a b c d e f g h
f 1
4 2
6 k 0 9 2 4 2 4 1 1
12 2 e h
9 8 p nil c d a c c d f
7 3
b d g
11 1 Q=[h,b]
a 5 c 4 v a b c d e f g h
f 1
4 2
6 k 0 9 2 4 2 4 1 1
while (Q ̸= ∅) 12
9
2 e h
p nil c d a c c d f
7 3 8
u = ExtractMin(Q) ; b d
1
g
Q=[b]
11
for each v adjacent to u
5 4
if ((v ∈ Q) a
4
c
2
f 1 v a b c d e f g h
6 k 0 9 2 4 2 4 1 1
& (w (u, v ) < key [v ])) 12 2 e h
p nil c a c
9 3 8 d c d f
7
p[v ] = u ; b d g
11 1 Q=[]
key [v ] = w (u, v ) ;
Prim’s Algorithm : time complexity analysis
Min Priority Queue :
▶ Min priority queue is the same as the max priority queue except it uses a
MinHeapify() routine as below.
▶ MinHeapify() always return the smallest element of an array as the root of the
heap.
▶ A call to min priority queue returns the root, the smallest element of the queue
MinHeapify(A, i)
l = Left(i) ; r = Right(i) ;
if (l ≤ heap size(A) & A[l] < A[i])
smallest = l ;
else
smallest = i ;
if (r ≤ heap size(A) & A[r] < A[smallest])
smallest = r ;
if (smallest != i)
Swap(A, i, smallest) ;
Heapify(A, smallest) ;
Prim’s Algorithm running time analysis
The total cost of the for loop is |E | × log n, i.e. O(|E | log n).
while loop is O(n lg n + E lg n). If |E | ≈ n2 , the dominant term of the while loop expression
is O(E lg n), this is the asymptotic cost of Prim’s algo.
Exercise on Prim’s algorithm
1
6 5
1
2 5 5 4
3 3 2
6 4
5 6
6
Exercise on Prim’s algorithm
Compute the MST using Prim’s algorithm. Fill the table at each step.
v a b c d e f
k
P
3
a e
1
9 4
3
b d
1
4
2
c 5
f