Greedy set cover
Each time, take the set covering the most elements not yet covered; at most H(max |S|) ≈ ln n times the fewest sets possible.
There is a universe X and a family of its subsets. We want the fewest subsets that together cover all of X (the
fewest experts who between them have every skill, say). The problem is NP-hard.
- Time:
O(|X| · |F| · min(|X|, |F|)) - Space:
O(|X| · |F|) - CLRS, section 35.3
12 elements and 6 sets (the CLRS example); greedy takes 4 sets where 3 would do.
def greedy_set_cover(S):# S[i][e] = 1 when set i contains element e (elements are numbered from 1 in the picture).m = len(S)n = len(S[0])sets = []for row in S:sets.append([e + 1 for e in range(n) if row[e] == 1])universe = sorted(set(e for s in sets for e in s))left = list(universe)chosen = []rows = [["S" + str(i + 1), sets[i], len(sets[i])] for i in range(m)] # for the picture: set, elements, new onescount = len(left)while left:best = 0for i in range(m):new = len([e for e in sets[i] if e in left])rows[i][2] = newif new > len([e for e in sets[best] if e in left]):best = ichosen.append("S" + str(best + 1))left = [e for e in left if e not in sets[best]]return chosen
Start
The table is still empty.
Local variables
Orange = changed in this step
S list
Call stack
- greedy_set_cover()line 1
Explanation
The problem
There is a universe X and a family of its subsets. We want the fewest subsets that together cover all of X (the
fewest experts who between them have every skill, say). The problem is NP-hard.
The greedy algorithm
While some element is uncovered, take the set covering the most uncovered elements.
The guarantee
CLRS proves that greedy uses at most H(d) times the optimal number of sets, where d is the size of the largest set
and H(d) = 1 + 1/2 + … + 1/d ≈ ln d. So it is a (ln n + 1)-approximation. It has been shown that (assuming
P ≠ NP) no much better approximation is possible.
The input
S is an incidence matrix: row i is the set S_i and column e the element e; a 1 means the element is in the
set.