This is a fairly typical packing problem. We can formulate it as an integer program like so. Let x_i
be 1
if we open station i
and 0
otherwise. Then the objective is to
n
maximize sum profit_i x_i.
i=1
The constraints are that we not open two stations within distance k
. We can slide a window of length k
over the stations, emitting a constraint for each maximal subset. For distance values l_1 = 5, l_2 = 15, l_3 = 23, l_4 = 30, l_5 = 38
and k = 16
, we have constraints
x_1 + x_2 <= 1 (y_1) { 5, 15}
x_2 + x_3 + x_4 <= 1 (y_2) {15, 23, 30}
x_3 + x_4 + x_5 <= 1 (y_3) {23, 30, 38}.
Finally, each station is open or not.
for all i, x_i in {0, 1}
Duality
The reason that we go to all of this trouble is as follows. First, we can relax the constraints by replacing x_i in {0, 1}
with x_i >= 0
. Now we have a linear program. We know that
value of linear program >= value of integer program,
because every solution to the integer program is a valid solution to the linear program. The beautiful thing about linear programs is that they have a dual program that, under certain technical constraints, by LP duality, satisfies
value of dual program = value of linear program >= value of integer program.
This matters because the dual program here is a minimization, so any old solution will give us a bound on the original integer program (i.e., the problem that we actually care about).
Dual program
This is derived mechanically from the linear program. I'll explain it intuitively below. General version:
m
minimize sum y_j
j=1
for all i, sum over windows j containing station i of y_j >= profit_i
for all j, y_j >= 0.
Concrete version (dual of the concrete LP above):
minimize y_1 + y_2 + y_3
y_1 >= profit_1 (x_1)
y_1 + y_2 >= profit_2 (x_2)
y_2 + y_3 >= profit_3 (x_3)
y_2 + y_3 >= profit_4 (x_4)
y_3 >= profit_5 (x_5).
y_1, y_2, y_3 >= 0.
Intuitively, we're figuring out how much to tax each window such that building any station is a break-even proposition. The less tax that we have to collect, the less valuable the stations.
Primal-dual approximation
The dual program can be solved by LP (possibly to integer optimality, actually; this is a shortest-path problem in disguise). Here's an approximation algorithm that's easier to implement.
Each y_i
is active if it appears on the left-hand side of an unsatisfied dual constraint. While some y_i
is active, we increase all active y_i
s continuously at the same rate. In practice, we figure out which constraint is satisfied first and then step time directly to that point.
Let's suppose that the constraints are as before and that
y_1 >= profit_1 = 1
y_1 + y_2 >= profit_2 = 2
y_2 + y_3 >= profit_3 = 4
y_2 + y_3 >= profit_4 = 5
y_3 >= profit_5 = 3.
Initially all variables are 0
and active. When they hit 1
, the profit_1
and profit_2
constraints are satisfied. Thus y_1
is deactivated, because it participates in no other constraint. We continue to increase y_2
and y_3
to 2
, and then the profit_3
constraint is satisfied. Both variables participate in the profit_4
constraint, so they remain active. When we increase to 2.5
, the profit_4
constraint is satisfied, and y_2
is no longer active. We continue, increasing y_3
to 3
for a final solution of y_1 = 1
and y_2 = 2.5
and y_3 = 3
, for value 6.5
. The optimum is (e.g.) y_1 = 1
and y_2 = 2
and y_3 = 3
, for value 6
.