Solve the set cover problem in Python

Set cover — pick the fewest sets whose union covers every element — models choosing sensor locations to watch every zone, features to hit every requirement, or servers to reach every region. The default answer online is a greedy pass; it approximates but doesn't optimize. With quicopt you get the provably smallest cover in a few lines of Python.

The naive approach

Greedy repeatedly grabs the set covering the most still-uncovered elements. It is simple and often decent, but it can use more sets than necessary and gives no optimality guarantee. Enumerating subsets is exponential. Model it instead.

Model it as a MILP

A binary x[s] selects set s. For every element, at least one selected set must contain it; minimize the number of sets chosen:

set_cover.py
from ortools.math_opt.python import mathopt
from quicopt import Client
sets = [{0,1,2},{2,3,4},{4,5,6},{6,7,0},{1,3,5,7},{0,2,4,6}]
universe = set(range(8))
M = len(sets)
model = mathopt.Model(name="set_cover")
x = [model.add_binary_variable(name=f"s{s}") for s in range(M)]
for e in universe:
    model.add_linear_constraint(sum(x[s] for s in range(M) if e in sets[s]) >= 1)
model.minimize(sum(x))
print(Client("https://try.quicoptapi.pgi.fz-juelich.de").solve(model).display)
$ python set_cover.py
├── status:     optimal
├── feasible:   true
├── objective:  2.0
├── x:          s0=0, s1=0, s2=0, s3=0, s4=1, s5=1  (6 variables)
└── solve_time: 0.0138 s

What you get

status: optimal means 2 sets is proven minimal: s4 = {1,3,5,7} and s5 = {0,2,4,6} cover all eight elements with nothing to spare. A greedy pass might have started with a three-element set and needed a third pick; the MILP finds the exact-cover pair and proves it optimal.

Switch the objective to minimize summed set costs and you have weighted set cover — same model, cheapest cover.

Next

Reference: R. M. Karp, Reducibility Among Combinatorial Problems, in Complexity of Computer Computations, 1972.

A bigger cover — or a different problem?

Tell us what you're optimizing. We'll help you model it and point you at the right approach.

Talk to us →

Frequently asked questions

Isn't the greedy algorithm the standard answer?

Greedy set cover is a good approximation but can miss the optimum — it's only guaranteed within a ln(n) factor. The MILP returns the provably smallest (or cheapest) cover.

What about weighted set cover?

Give each set a cost and minimize the total instead of the count — one word changes in the objective; the model stays the same.

Is quicopt free to use?

Yes — pip install quicopt and your first call sets up a free key, no license.