GreedyAlgorithms
GreedyAlgorithms
21 juin 2021
Outline
Huffman’s encoding
Exercises
Greedy algorithms
Then objects are put in the knapsack according to this greedy criterion
if their weight is smaller than the residual capacity of the knapsack
A greedy algorithm for 0-1 knapsack
Object i 1 2 3 4 5
Weight wi 2 3 5 6 4
Value vi 6 1 12 8 7
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 in objects[n] objects along values
for (i = 1; i ≤ n, i + +)
j = objects[i]
if (w > wj )
selected objects[i] = j
w = w − wj
i ++
objects = [3, 4, 5, 1, 2] after sorting
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 in objects[n] objects along weights
for (i = 1; i ≤ n, i + +)
j = objects[i]
if (w > wj )
selected objects[i] = j
w = w − wj
i ++
objects = [1, 2, 5, 3, 4] after sorting
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 in objects[n] objects along density wv [i]
[i]
for (i = 1; i ≤ n, i + +)
j = objects[i]
if (w > wj )
selected objects[i] = j
w = w − wj
i ++
objects = [1, 3, 5, 4, 2] after sorting
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 algorithms fail
We have just see that greedy algorithm for the same 0-1 knapsack problem instance
returns 3 different solutions !
This because greedy algorithms may fail to solve some optimization problems to
optimality, this is the case for 0-1 knapsack and the making change problem
There are other optimization problems for which greedy work perfectly well, in this
case greedy is a wonderful algorithm because it is simple and computationally very
efficient (low asymptotic complexity)
Greedy works when a problem satisfies a second condition (beside the optimal
substructure condition) : the greedy choice condition
There could also be more than one MST for a same graph. In this
example, 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
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 no 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) 6= 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) 6= 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) 6= 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) 6= 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) 6= 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 ) ;
output : A minimum spanning tree T ;
Sort E by increasing length ;
n = |V | ;
I Sort edges : O(E lg E )
T = ∅; I O(n) MakeSet()’s
for each v ∈ V MakeSet(v)
for i = 1 to |E | do
I O(E ) FindSet()’s Union()’s
shortest {u, v } not yet considered ; operations
if (FindSet(u) 6= FindSet(v)) then
Union(FindSet(u),
S FindSet(v))
T = T {u, v } ;
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 6= ∅)
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 6= ∅) 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 6= ∅) 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 6= ∅) 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
Prim MST(G , r )
∀u∈G Priority Queue : O(n)
key [u] = Max Int ; while loop runs n times
key [r ] = 0 ;
I ExractMin cost O(lg n), total
p[r ] = NIL ;
Q = MinPriorityQueue(V ) O(n lg n)
while (Q 6= ∅) I for loop is executed 2|E | times
u = ExtractMin(Q) ;
for each v adjacent to u
(Amortized analysis)
if ((v ∈ Q) & (w (u, v ) < key [v ])) I Each time could potentially
p[v ] = u ; change key [v ], O(lg n)
key [v ] = w (u, v ) ;
I Total cost of for loop is
O(E lg n)
while loop is
O(n lg n + E lg n) ∈ O(E lg n)
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
The single-source shortest paths problem
10 1 50
5 100 30 2
10 20 5
4 50 3
Greedy aspects of Dijkstra’s algorithm
Step v C D S
10 1 50 init {2,3,4,5} {50,30,100,10} {1}
5 100 30 2 1 5 {2,3,4} {50,30,20,10} {1,5}
10 20 5 2 4 {2,3} {40,30,20,10} {1,4,5}
4 50 3 3 3 {2} {35,30,20,10} {1,3,4,5}
{1,2,3,4,5}
Initially, the path from s to any other node x is the direct edge (s, x)
These edges are sorted in increasing order of their length, greedy algo selects the
shortest edge (s, y ) among them, this become the first shortest path
Then Dijkstra’s algo re-calculate the distance of the path from s to any node other
node x (different from y ) using the shortest path (s, y ) and edge (y , x) if such an
edge exist
Those paths are sorted in increasing order of their length, greedy algo (Dijkstra)
selects the shortest one, this become the second shortest path
Greedy aspects of Dijkstra’s algorithm
Step v C D S
10 1 50 init {2,3,4,5} {50,30,100,10} {1}
5 100 30 2 1 5 {2,3,4} {50,30,20,10} {1,5}
10 20 5 2 4 {2,3} {40,30,20,10} {1,4,5}
4 50 3 3 3 {2} {35,30,20,10} {1,3,4,5}
{1,2,3,4,5}
In general, each time a new shortest path (s, ..., y ) has been found,
I Dijkstra’s algo re-calculate the distance from the source node s to any other
node x for which the shortest path (s, ..., x) is yet to be found
I The re-calculation is obtained by creating a path (s, ..., y , x), if this path is
shortest than the existing path (s, ...x), then the length of (s, ..., y , x)
becomes the lenght of the path from s to x.
I Then Dijkstra selects the shortest of all these paths that link s to a node x for
which the shortest path has not yet be computed
Dijkstra’s algorithm
Step v C D S
10 1 50 init {2,3,4,5} {50,30,100,10} {1}
5 100 30 2 1 5 {2,3,4} {50,30,20,10} {1,5}
10 20 5 2 4 {2,3} {40,30,20,10} {1,4,5}
4 50 3 3 3 {2} {35,30,20,10} {1,3,4,5}
{1,2,3,4,5}
Here each time a new shortest path is computed, the distance from the source node
to all the other nodes is re-calculated and stored into the distance vector D.
Algorithm Dijkstra(G )
C = {2, 3, . . . , n} {S = V \ C }
for i = 2 to n do D[i] = L[1, i]
repeat n − 2 times
v = some element of C minimizing D[v ]
C = C \ {v }
for each w ∈ C do
D[w ] = min(D[w ], D[v ] + L[v , w ])
return D
Dijkstra’s algorithm : time complexity analysis
Algorithm Dijkstra(G )
C = {2, 3, . . . , n} {S = V \ C }
for i = 2 to n do D[i] = L[1, i]
repeat n − 1 times
v = some element of C minimizing D[v ]
C = C \ {v }
for each w ∈ C do
D[w ] = min(D[w ], D[v ] + L[v , w ])
return D
To find the shortest path from a node v to the source just follow the
pointers in reverse direction starting at v
Algorithm Dijkstra(G )
C = {2, 3, . . . , n} {S = V \ C }
for i = 2 to n do
D[i] = L[1, i]
P[i] = 1
repeat n − 1 times
v = some element of C minimizing D[v ]
C = C \ {v }
for each w ∈ C do
if D[w ] > D[v ] + L[v , w ] then
D[w ] = min(D[w ], D[v ] + L[v , w ])
P[w ] = v
return D and P
Dijkstra’s algorithm : obtaining the shortest paths
Here are consecutive states of P for the previous example :
Step v C D S
10 1 50 init {2,3,4,5} {50,30,100,10} {1}
5 100 30 2 1 5 {2,3,4} {50,30,20,10} {1,5}
10 20 5 2 4 {2,3} {40,30,20,10} {1,4,5}
4 50 3 3 3 {2} {35,30,20,10} {1,3,4,5}
{1,2,3,4,5}
P 1 2 3 4 5
I v =5
1 1 1 5 1
P 1 2 3 4 5
I v =4
1 4 1 5 1
P 1 2 3 4 5
I v =3
1 3 1 5 1
P 1 2 3 4 5
I v =2
1 3 1 5 1
Exercise : single-source shortest paths
Compute the single-source shortest paths for the oriented graph below.
The source is node s.
Algorithm Dijkstra(G )
C = {2, 3, . . . , n} {S = V \ C }
for i = 2 to n do D[i] = L[1, i]
repeat n − 1 times
v = some element of C minimizing D[v ]
C = C \ {v }
for each w ∈ C do
D[w ] = min(D[w ], D[v ] + L[v , w ])
return D
Exercise : single-source shortest paths
Compute the length as well as the single-source shortest paths for the
oriented graph below. The source is node 1.
9 5
6
2
2
11 6
14 3
9 10
15
7
4
Exercise : single-source shortest paths
Compute the length as well as the single-source shortest paths for the
oriented graph below. The source is node 1.
4
20
10
10
5 5
1
30
30 20
20
2 3
40
Encoding data : Huffman algorithm
Huffman algorithm build prefix codes that are optimal in terms of the
number of bits needed to encode a text
Notice that some characters, (e.g. q, x, z, v) are rare, and others (e.g.
e, s, t, a) are common.
It might make more sense to use less bits to store the common
characters, and more bits to store the rare characters.
A code is called optimal if the space required to store data with the
given distribution is a minimum.
The problem with this encoding is that the string could also be ktve.
Variable length code example
To do this requires more space, and may make the code worse than a
fixed-length code. Rather we use a prefix code.
Prefix codes
The most obvious way is to read one bit, see if it is a character, read
another, see if the two are a character, etc. : not very efficient.
Decoding prefix codes
Letters A T V E R Z K L
Frequency 20 15 3 23 19 2 7 13
Encoding 00 100 11100 01 101 11101 1111 110
Decode 01111011010010100100
Letters A T V E R Z K L
Frequency 20 15 3 23 19 2 7 13
Encoding 00 100 11100 01 101 11101 1111 110
0 1
0 1 0 1
A E 0 1 0 1
T R L 0 1
0 1 K
V Z
Since the less frequent nodes should end up near the bottom of the
tree, it makes sense that we should consider these first.
i c l n f o a t h p u
9 4 3 3 2 2 2 1 1 1 1
9:i 4:c 3:l 3:n 2:f 2:o 2:a 1:t 1:h 1:p 1:u
1:p 1:u
9:i 7 5 4:c 4
9:i 5 4:c 4 4 3:n
1:p 1:u
9:i 8 7 5
1:p 1:u
9:i 8 7 5 17 12
9:i 8 7 5
4:c 4 4 3:n 3:l 2
1:p 1:u
12 9:i 8 29
7 5 17 12
4:c 4
7 5
4 3:n 3:l 2 9:i 8
2:o 2:a
4:c 4 3:n 3:l 2
2 2:f 1:t 1:h 4
1:p 1:u
17 12
0 1
9:i 8 7 5
0 1 0 1
4:c 4 3:n 3:l 2 i
4
0 1 0 1 0 1
2 2:f 1:t 1:h c n
2:o 2:a l
0 1 0 1 0 1
1:p 1:u
o a f t h
0 1
p u
We can now list the code :
0 1
0 1 0 1
i
0 1 0 1 0 1
c n l
0 1 0 1 0 1
o a f t h
0 1
p u
The algorithm for Huffman encoding will build a tree from the nodes in
a bottom-up fashion.
Huffman encoding algorithm & complexity analysis
We are given an array of jobs where every job has a deadline and
associated profit if the job is finished before the deadline
Every job takes a single unit of time, so the minimum possible deadline
for any job is 1. The objective is to maximize the total profit when only
one job can be scheduled at a time
i 1 2 3 4 5 6 7 8 9 10 11
si 1 3 0 5 3 5 6 8 8 2 12
fi 4 5 6 7 8 9 10 11 12 13 14
Two activities i and j are said to be non-conflicting if si ≥ fj or sj ≥ fi
(the two activities do not overlap).
Greedy algo : Sort the activities in increasing order of their finish time
(greedy criterion). Then :
I Select the activity with the earliest finish
I Eliminate the activities that overlap with the selected activity
I Repeat !
Activity scheduling problem
i 1 2 3 4 5 6 7 8 9 10 11
si 1 3 0 5 3 5 6 8 8 2 12
fi 4 5 6 7 8 9 10 11 12 13 14
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Activity scheduling problem : greedy choice property
Give a greedy algorithm that schedules the tasks to minimize the average
completion time. Each task runs non-preemptively, once task ti starts, it must run
continuously for pi units of time.