Lecture 16
- DP for hard problems
- Non-trivial exponential time
- Approximation algorithms
- Reduced precision
def RSP2(G, s, t, L):
best <- RSP2(G, s, t, L/2)
for each u in V do:
best <- min(best, RSP2(G, s, u, L/2) + RSP2(G, u, t, L/2))
def DP2SP:
initialize D[v, w, l], v in V, w in V, l in {0, ..., ceil(log(n))} to infinity.
for u in V: D[u, u, 0] <- 0
for u in V, v in N(u): D[u, v, 0] <- w((u, v))
for l = 1 to ceil(log(n)):
for v in V, w in V:
best <- D[v, w, l - 1]
for u in V:
best <- min(best, D[v, u, l - 1] + D[u, w, l - 1])
D[v, w, l] <- best
return (D[v, w] = D(v, w, ceil(log(n)))
The above has complexity \( O(n ^ 3 \log n) \). Recall Bellman-Ford is \( O(|V| |E|) \), but recall this algorithm gives all pairs distances where BF only gives the distance between a fixed pair. There's another even better algorithm called Floyd's. This one is sometimes called the "matrix-multiply based algorithm", but the name is confusing.
Hamiltonian Path
For the problem of finding a longest path, we'll need to require the path be simple.
def RHP(G, s):
if |V| = 1 return True;
for each u in N(s):
if RHP(G - {s}, u): return True;
return False;
The above has complexity \( O((n-1)!) \).
def DPHP:
initialize H[S, u], S a subset of V, u in V
for u in V:
H[{u}, u] <- True
for k = 2 to n:
for each S a subset of V, where |S| = k and each s in S:
found <- False
for each u in intersect(N(s), S):
if H[S -{s}, u]:
found <- True
H[S, s] <- found
return H[V, s]
The above has \( O(n 2 ^ n) \) subproblems and \( O(n^2 2^n) \) complexity.
Min makespan
2-machine scheduling. Time jobs will take: a1, a2, ..., an. Assign each job to a machine to minimize the time all jobs are finished. The problem is NP-hard, but there is a poly-time algorithm in n and \( \max a_i \leq 2^l \). \( O(n ^ {O(1)} 2 ^ l) \).
We'll need to keep track of the difference between the total time scheduled to the two machines.
def RMM(a1, ..., an, L1, L2):
if n == 0: return max(L1, L2)
return min(RMM(a2, ..., an, L1 + a1, L2), RMM(a2, ..., an, L1, L2 + a1))
Let \( A = \max a_i \). Note \( L_1 \leq i A \) at step \( i \), and \( L_2 = \sum_{j = 1}^i a_j - L_1 \).
def DPM(a1, ..., an):
Sum <- sum(ai)
A <- max ai
initialize LB[I, L1]
for L1 = 0 to n * A:
LB[n+1, L1] <- max(L1, Sum - L1)
for I = n down to 1
for L1 = 0 to (I-1) * A
LB[I, L1] <- min (LB[I + 1, L1 + a], LB[I + 1, L1])
return LB[1, 0]
Approximation
Within a factor of \( 1 + \epsilon \). Define Sum as the sum of the ai. \( B := \epsilon Sum / (2n) \). Define aiHat = ceil(ai/B).