0% found this document useful (0 votes)
43 views9 pages

Problem Set #6 Solutions: General Notes

- Gabow's scaling algorithm can be used to find single-source shortest paths faster than Dijkstra's algorithm when edge weights are positive integers bounded by the number of edges. - It works by maintaining distance estimates based on the binary representation of edge weights, showing estimates between levels differ by at most the number of vertices. - Transforming the weights by adding appropriate distance estimates results in new weights that are always nonnegative integers, allowing shortest paths to be solved quickly.

Uploaded by

randomrandom221
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views9 pages

Problem Set #6 Solutions: General Notes

- Gabow's scaling algorithm can be used to find single-source shortest paths faster than Dijkstra's algorithm when edge weights are positive integers bounded by the number of edges. - It works by maintaining distance estimates based on the binary representation of edge weights, showing estimates between levels differ by at most the number of vertices. - Transforming the weights by adding appropriate distance estimates results in new weights that are always nonnegative integers, allowing shortest paths to be solved quickly.

Uploaded by

randomrandom221
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

CS161: Design and Analysis of Algorithms Summer 2004

Problem Set #6 Solutions


General Notes
• Regrade Policy: If you believe an error has been made in the grading of your problem
set, you may resubmit it for a regrade. If the error consists of more than an error in
addition of points, please include with your problem set a detailed explanation of
which problems you think you deserve more points on and why. We reserve the right
to regrade your entire problem set, so your final grade may either increase or decrease.

Throughout this entire problem set, your proofs should be as formal as possible. However,
when asked to state an algorithm, you do not need to give pseudocode or prove correctness
at the level of loop invariants. Your running times should always be given in terms of |V |
and/or |E|. If representation of the graph is not specified, you may assume whichever is
convenient.

1. [19 points] Gabow’s Scaling Algorithm for Single-Source Shortest Paths

(a) [5 points] Do problem 24-4(a) on page 616 of CLRS.


Answer: Since the edge weights are all positive, we can use Dijkstra’s algorithm
to find the shortest paths from the start vertex to all other vertices. The running
time of Dijkstra’s algorithm using a binary heap is O(E lg V ). The lg V term
comes from the V calls to extract-min and the E calls to decrease-key.
Because of the constraints that the edge weights are integers and that the shortest
path distances are bounded by |E|, we can do better. We can use a method similar
to counting sort to maintain the list of vertices. We know that the weights of the
path to each vertex will always be an integer between 0 and |E|, so we can keep an
array SHORTEST of linked lists for each possible value. For Dijkstra’s algorithm,
we need to implement the INSERT, DECREASE-KEY, and EXTRACT-MIN
functions. INSERT is easy. If we want to insert a vertex that is reachable in
length i, we simply add it to the beginning of the linked list in SHORTEST[i],
which is O(1). To call DECREASE-KEY on a vertex v, we remove v from it’s
current linked list (O(1)), decrease it’s key to i, and insert it into SHORTEST[i],
for a total time of O(1). To EXTRACT-MIN, we notice that throughout the
running of Dijkstra’s algorithm, we always extract vertices with shortest paths of
non-decreasing value. So, if the previous vertex was extracted at value i, we know
that there can be no vertices in the array at values less than i. So, we start at
SHORTEST[i] and if it is non-empty, we remove the first element from the linked
list. If it is empty, we move up to SHORTEST[i + 1] and repeat. The actual
extraction takes time O(1). Notice that the scanning for a non-empty list could
take time O(E) since there are a total of E lists, but since we never backtrack,
Problem Set #6 2

this O(E) scan of the lists is averaged over the O(V ) calls to EXTRACT-MIN,
for an amoritized cost of O(E/V ) each.
Our total running time therefore includes V calls to INSERT (O(V )), E calls
to DECREASE-KEY (O(E)) and V calls to EXTRACT-MIN (O(V + E)) for a
total running time of O(V + E). Since we know |E| > |V | − 1, the O(E) term
dominates for a running time of O(E).
(b) [1 point] Do problem 24-4(b) on page 616 of CLRS.
Answer: Using part (a), we can show how to compute δ1 (s, v) for all v ∈ V in
O(E) time. We know that δ1 (s, v) is computed using the edge weight function
w1 , which only uses the first significant bit of the actual edge weights. Therefore,
the weights w1 are always either 0 or 1. The maximum number of edges on a
shortest path is |V | − 1 since it can have no cycles. Since the maximum edge
weight w1 is 1, the maximum weight of a shortest path is |V | − 1. Therefore, we
have the condition that for all vertices v ∈ V , we have δ1 (s, v) ≤ |V | − 1 ≤ |E| by
assumption. From part (a), we know that we can compute δ1 (s, v) for all v ∈ V
in O(E) time.
(c) [3 points] Do problem 24-4(c) on page 616 of CLRS.
Answer: We know that wi is defined as bw(u, v)/2k−ic. We will show that either
wi (u, v) = 2wi−1 (u, v) or wi (u, v) = 2wi−1 (u, v) + 1. Weight wi is the i most
significant bits of w. We can get wi from wi−1 by shifting wi−1 to the left by
one space and adding the ith significant bit. Shifting to the left is equivalent to
multiplying by 2 and the ith significant bit can be either 0 or 1. So, we have that
wi (u, v) = 2wi−1 (u, v) if the ith significant bit is a zero or wi (u, v) = 2wi−1 (u, v)+1
if the ith significant bit is a one.
We now want to prove that 2δi−1 (s, v) ≤ δi (s, v) ≤ 2δi−1 (s, v) + |V | − 1. The
shortest path δi (s, v) has weight

X
δi (s, v) = min wi (e)
e∈P ath(s,v)
X
≥ min 2wi−1 (e)
e∈P ath(s,v)
X
= 2 · min wi−1 (e)
e∈P ath(s,v)

= 2δi−1 (s, v)

with the inequality holding because the wi (e) is greater than or equal to 2wi−1 (e)
since it equals either that or that plus one. The last equality holds because the
minumum weight of any path from s to v using the weight function wi−1 is equal
to the shortest path distance from s to v using wi−1 .
Similarly,
Problem Set #6 3

X
δi (s, v) = min wi (e)
e∈P ath(s,v)
X
≤ min (2wi−1 (e) + 1)
e∈P ath(s,v)
 
X X
= min 2 wi−1 (e) + 1
e∈P ath(s,v) e∈P ath(s,v)
 
X
≤ min 2 wi−1 (e) + |V | − 1
e∈P ath(s,v)

= 2δi−1 (s, v) + |V | − 1

The first inequality holds because wi (e) is less than or equal to 2wi−1 (e) + 1 by
similar reasoning as above. We then set the minimum weight of any paths from
s to v using the weight function wi−1 equal to the shortest path as above. The
second inequality holds because the minimum path length is bounded by |V | − 1
because it can have no cycles.
(d) [3 points] Do problem 24-4(d) on page 616 of CLRS.
Answer: We define for i = 2, 3, . . . k and all (u, v) ∈ E,

ŵi (u, v) = wi (u, v) + 2δi−1 (s, u) − 2δi−1 (s, v)

We wish to prove for all i = 2, 3, . . . , k and all u, v ∈ V that ŵi of edge (u, v) is a
nonnegative integer. We can prove this starting from the triangle inequality.

δi−1 (s, v) ≤ δi−1 (s, u) + wi−1 (u, v)


2δi−1 (s, v) ≤ 2δi−1 (s, u) + 2wi−1 (u, v)
2δi−1 (s, v) ≤ 2δi−1 (s, u) + wi (u, v)
0 ≤ wi (u, v) + 2δi−1 (s, u) − 2δi−1 (s, v)
0 ≤ ŵi

Thus, ŵi is never negative. It is an integer since all the edge weights are always
integers and thus all the shortest path distances are always integers.
(e) [4 points] Do problem 24-4(e) on page 617 of CLRS.
Answer: We define δˆi (s, v) as the shortest path weight from s to v using ŵi . We
want to prove for i = 2, 3, . . . k and all v ∈ V that

δi (s, v) = δˆi (s, v) + 2δi−1 (s, v)


Problem Set #6 4

and that δˆi ≤ |E|.


We prove this by expanding the δˆi (s, v) term.

δˆi (s, v) = min


X
ŵi(e)
e∈P ath(s,v)

= min(ŵi(s, x1 ) + ŵi (x1 , x2 ) + · · · + ŵi (xn , v))


= min(wi(s, x1 ) + 2δi−1 (s, s) − 2δi−1 (s, x1 )) +
(wi (x1 , x2 ) + 2δi−1 (s, x1 ) − 2δi−1 (s, x2 )) + · · · +
(wi (xn , v) + 2δi−1 (s, xn ) − 2δi−1 (s, v))
X
= min(2δi−1 (s, s) − 2δi−1 (s, v) + wi (e))
e∈P ath(s,v)
X
= −2δi−1 (s, v) + min wi (e)
e∈P ath(s,v)

= −2δi−1 (s, v) + δi (s, v)


δi (s, v) = δˆi (s, v) + 2δi−1 (s, v)

We expand δˆi (s, v) in terms of the weights of edges along the path. We see that
if we also expand the ŵi terms, many things cancel. The term δi−1 (s, s) = 0
since the shortest path from a node to itself is zero regardless of the edge weight
function. Also, we know that the minimum path length from s to v using the wi
function is δi (s, v).
From this, we can easily show that δˆi ≤ |E| using the results from part (c).

δi (s, v) = δˆi (s, v) + 2δi−1 (s, v)


2δi−1 (s, v) + |V | − 1 ≥ δˆi (s, v) + 2δi−1 (s, v)
δˆi (s, v) ≤ 2δi−1 (s, v) + |V | − 1 − 2δi−1 (s, v)
δˆi (s, v) ≤ |V | − 1
δˆi (s, v) ≤ |E|

(f) [3 points] Do problem 24-4(f) on page 617 of CLRS.


Answer: If we are given δi−1 (s, v), we can compute ŵi (u, v) using the equation
in part (d) in time O(E) since we can easily calculate wi (u, v) and we need to
compute it for each edge. In part (e), we showed that δˆi (s, v) is bounded by |E|.
So, we can use the results from part (a) to compute the shortest path distances
δˆi (s, v) in time O(E). From these results, we can use the equation in part (e) to
calculate the shortest path distances δi (s, v) in time O(V ), once for each vertex.
Therefore, we can compute δ(s, v) in time O(E lg W ). We will simply start by
calculating δ1 (s, v) in time O(E) as we showed in part (b). Then, as we just
explained, we can calculate each δi+1 from δi in time O(E). In total, we need to
calculate up till δk . Since k = O(lg W ), the running time of this is O(E lg W ).
Problem Set #6 5

2. [12 points] Transitive Closure of a Dynamic Graph

(a) [3 points] Do problem 25-1(a) on page 641 of CLRS.


Answer: When we add a new edge to a graph, we need to update the transitive
closure. The only new paths we will add are the ones which use the new edge
(u, v). These paths will be of the form a ; u → v ; b. We can find all these
new paths by looking in the old transitive closure for the vertices a ∈ A which
had paths to u and for vertices b ∈ B which v had paths to. The new edges in the
transitive closure will then be (a, b), where a ∈ A and b ∈ B. Since the number
of vertices in each set A or B is bounded by V , the total number of edges we’ll
need to add is O(V 2 ). If we represent the transitive closure graph G∗ with an
adjacency matrix, we can very easily find the sets A and B. A will be all the
vertices which have a one in the column u and B will be all the vertices which
have a one in the row v.
(b) [1 point] Do problem 25-1(b) on page 641 of CLRS.
Answer: Suppose our graph G consists of two disjoint graphs, each of size V /2.
Assume that each subgraph is complete, that there are edges between each vertex
in the subgraph to all other vertices in the same subgraph. If we then add an edge
from a vertex in the first subgraph to one in the second subgraph, we will need
to add edges in the transitive closure from every vertex in the first subgraph to
every vertex in the second subgraph. This is a total of V /2 × V /2 = V 2 /4 edges.
Regardless of what our algorithm is for calculating the transitive closure, we will
always need to add Ω(V 2 ) edges, and thus the running time must be Ω(V 2 ).
(c) [8 points] Do problem 25-1(c) on page 641 of CLRS.
Answer: We will give you an outline of the solution to this problem on the final
exam. You will then complete it and analyze its correctness and running time.

3. [24 points] Assorted Graph Problems

(a) [8 points] Do problem 22.2-7 on page 539 of CLRS. Assume the edges of T
are undirected and weighted, and give your running time in terms of |V | (since
|E| = |V | − 1).
Answer: First notice that the shortest path distance between two vertices is
given by the length of the path between the two vertices, since there is only one
path between any pair of vertices in a tree. So, we are basically asking for the
longest simple path between any two leaves in a tree.
We will keep two items of information at each edge (u, v) ∈ T . We will keep
d[u → v], which represents the longest simple path distance in the tree from u to
v to any leaf. Also, we keep d[v → u], defined symmetrically.
First we arbitrarily root the tree at some vertex r by pointing all the edges outward
from r. We will compute the downward distances bottom-up, and then the upward
distance top-down.
Problem Set #6 6

COMPUTE-DOWN(x)
1 if IsLeaf(x)
2 return
3 for y ∈ children(x)
4 COMPUTE-DOWN(y)
5 d[x → y] ← w(x, y) + maxz∈children(y) d[y → z]
After calling COMPUTE-DOWN on the root of the tree r, every edge will have
its downward field set. Notice that because of the recursion, the information is
actually first computed at the leaves and then propagated upward.
The top-down pass is somewhat tricker, because now we must integrate
information from different branches as we descend down the tree. There are
two differences: first, the information is now computed at the top first, and at
the bottom at the end; second, updating d[y → x] where x is the parent of y now
depends not only on d[x → p(x)] but also on d[x → z], where z are other children
of x. However, these values were computed on the downward pass; therefore, as
long as we compute d[x → p(x)] before d[y → x], we have all the information we
need.
COMPUTE-UP(x)
1 p ← parent(x)
2 for y ∈ children(x)
3 d[y → x] ← w(x, y) + maxz∈children(x)∪{p},z6=y d[x → z]
4 COMPUTE-UP(y)
Thus, to calculate the diameter, we root the tree arbitrarily at a vertex r, call
COMPUTE-DOWN(r) and then COMPUTE-UP(r). The largest value d[u → v]
computed during these procedures is indeed the diameter of the tree.
The first procedure clearly runs in O(V ), since every edge u → v is examined at
most twice - once when we d[u → v], and once when we set d[p(u) → u].
The second procedure as it is written runs in worst-case time O(V 2 ), since if we
have a node with Θ(V ) chilren, we will be looking through all the downward
distance values V times for each maximization step in line 3. However, we notice
that the only useful values from that step are the two largest downward x → z
values, since at most one such z can be the y we are currently looking at. Thus,
we precompute at each node x the two largest x → z values, and then use the
largest unless z = y. Thus, each edge is considered at most a constant number of
times, and the running time is O(V ) as well.
(b) [8 points] Do problem 22-3(b) on page 559 of CLRS. You may assume the result
of 22-3(a) without proof.
Answer: From part (a), we know that if there is an Euler tour in the graph G,
then the in-degree equals the out-degree for every vertex v. Because of this fact,
we know that if we pick a path with unique edges, any time we reach a vertex
(use one of the in-degree edges), there must still be a way to leave the vertex (use
one of the out-degree edges) except for the first vertex in the path.
Our algorithm therefore is to pick a random starting vertex v. We pick an outgoing
Problem Set #6 7

edge from v, (v, u), at random. We move to vertex u and delete edge (v, u) from
the graph and repeat. If we get to a vertex with no outgoing edges and it is not
equal to v, we report that no Euler tour exists. If the vertex with no outgoing
edges is v, we have a cycle, which we represent as v → u → · · · → v.
The problem is that we may not have visited all the edges in the graph yet. This
may only occur if there are vertices in our cycle which have outgoing edges that
we didn’t traverse. Otherwise, our graph would not be connected. If we can
efficiently pick one of these vertices u and start a cycle from that point, we know
that the new cycle from u will end at u by the same reasoning as above. Therefore,
we can connect the two cycles {. . . a → u → b . . . } and {u → c · · · → d → u} by
making one big cycle {. . . a → u → c · · · → d → u → b . . . }. This is a valid cycle
since we removed all the edges in the first cycle before computing the second cycle,
so we still have the property that each edge is used at most once. We assume
that when we start the new cycle from u, we keep a pointer to the position of u
in the old cycle so that we know where to break the old cycle in constant time.
If we repeat this process until there are no more edges in the graph, we will
have an Euler tour. The only problem is how to pick the vertex u that still has
outgoing edges from the current cycle. Our original vertex was v. For the first
cycle created, we simply walk along the cycle from v and let u equal the first
vertex which still has outgoing edges. Then, after adding the next cycle, we start
walking from u along the newly merged cycles and so on. Once we have traversed
the path from v ; u, we know that none of the vertices in that section can ever
have outgoing edges, so we don’t need to consider them the second time. We will
need to walk over the entire Euler tour at some point in the algorithm, so the
total running time of finding the vertex u for all the cycles is O(E). Also, the
cost of actually finding the cycles traverses each edge exactly once, so it is also
O(E). Therefore, the total running time of the algorithm is O(E).
(c) [3 points] Suppose we have a single-source shortest path algorithm A that runs
in time f (|V |, |E|) when all edge weights are nonnegative. Give an algorithm to
solve problem 24.3-4 on page 600 of CLRS in time f (|V |, |E|) + O(E) by using A
as a subroutine.
Answer: The reliability of a path from u to v is the product of the reliabilities
of each edge in the path. This is because the probability that the channel does
not fail is the probability that all individual edges do not fail. Since the failures
or successes of the individual edges are independent, we simply multiply to get
the total probability of success.
But, our shortest path algorithm finds the shortest path by summing the edge
weights. We need some transformation of our reliabilities so that we can use the
shortest path algorithm given. One function we have seen that converts a product
of terms to a sum of terms is the log function.
If we define a new weight function w(u, v) = − lg(r(u, v)), then all the edge
weights are positive since the log of a positive number less than 1 is negative. As
the reliability decreases, the value of the weight of the edge will increase. Since
we are trying to find the most reliable path, this will correspond to the shortest
Problem Set #6 8

weight path in the graph with the new edge weights.


We can show this more formally, where RPATH represents the reliability of a
path.

Y
RP AT H(s, t) = r(e)
e∈P ath(s,t)
X
log RP AT H(s, t) = log r(e)
e∈P ath(s,t)
X
− log RP AT H(s, t) = − log r(e)
e∈P ath(s,t)

Since the log function is monotonic as long as the base is greater than 1, if we
find the minimum path with edge weights w, we will also find the most reliable
path.
The time for the conversion to the weight function w is constant for each edge,
so the total time is O(E). We then call the single-source shortest path algorithm
which runs in time f (|V |, |E|) and returns our most reliable path. Therefore, the
total running time is f (|V |, |E|) + O(E).
(d) [5 points] Do problem 25.2-9 on page 635 of CLRS.
Answer: If we have an algorithm to compute the transitive closure of a directed
acyclic graph, we can use it to calculate the transitive closure of any directed
graph. We first decompose the directed graph G into its strongly connected
component graph GSCC . This runs in time O(V + E) and results in a graph with
at most V vertices and E edges. We keep track of which set of vertices in G
map to each vertex in GSCC . Call this g(v) which returns a stronly connected
component in GSCC . We then call the transitive closure algorithm on the graph
GSCC . This runs in time O(f (|V |, |E|)). All that is left is to convert back from the
strongly connected component graph’s transitive closure to G’s transitive closure.
There is an edge (u, v) in the transitive closure of G if and only if there is an edge
(g(u), g(v)) in the graph GSCC . The forward direction is easy to see. If there
is a path from u to v in G, then there must be a path between the component
that u belongs to and the one that v belongs to in GSCC . The reverse direction
is equally easy. If there is a path between u’s strongly connected component and
v’s strongly connected component in GSCC , then there is a path between some
vertex a in g(u) and some vertex b in g(v) in G. But, since u and a are in the
same SCC, there is a path from u ; a and since v and b are in the same SCC,
there is a path from v ; b. Therefore, there is a path u ; a ; b ; v in G.
To actually calculate the transitive closure of G this way would require time V 2
since we’d need to look at all pairs. Instead, we will look at the transitive closure
of GSCC . For each edge (a, b) in the transitive closure of GSCC , we assume that
we know the set of vertices in G that map to a and b, call these sets g −1(a) and
g −1 (b) respectively. We will add the edge (x, y) for all vertices x ∈ g −1(a) and
Problem Set #6 9

y ∈ g −1 (b). This will take time equal to the number of edges in the transitive
closure of G, O(E ∗ ).
Therefore the total running time for the algorithm is the time to build the strongly
connected components (O(V +E)), the time to run the transitive closure algorithm
on GSCC (O(f (|V |, |E|)) and the time to convert back to the transitive closure of
G (O(E ∗ )). Since we know that E < E ∗ , the total time is O(f (|V |, |E|)+V +E ∗ ).

You might also like