Albert-Ludwigs-Universität, Inst. für Informatik Prof. Dr. Fabian Kuhn

Albert-Ludwigs-Universität, Inst. für Informatik
Prof. Dr. Fabian Kuhn
S. Daum, A. Ghodselahi, O. Saukh
December 3, 2013
Algorithm Theory, Winter Term 2013/14
Sample Solution 3
Exercise 1: Sub-Sequences
(a) Consider a sequence A = a1 , a2 , . . . , am of characters. A sub-sequence S of A is a sequence
that can be obtained by deleting some characters in A. Hence, for example, a, r, e, w, a, a
is a sub-sequence of b, a, a, r, e, z, w, a, b, a. Given two sequences A of length m and B of
length n, describe an O(m · n) time dynamic programming algorithm to compute the length
of a longest common sub-sequence of A and B! To describe the algorithm, specify the subproblems you need to solve (and store in a table), the initialization, as well as the recursive
rule to compute the sub-problems.
(b) Apply your algorithm to the inputs A = a, e, a, a, g, s, s, t, and B = b, a, e, b, s, a, g, t by
setting up and filling out the table you need. Explain how you get the length of the longest
common sub-sequence from your table. Also show how to compute a longest common subsequence of A and B.
(c) For two character sequences A and B, a super sequence C is a character sequence such that
both A and B are sub-sequences of C. Give an efficient algorithm for finding the shortest
common super-sequence of two strings A and B.
Hint: Try to find a connection between the longest common sub-sequence of A and B and
the shortest common super-sequence of A and B.
Solution:
(a) Assume that the sequences A and B are in arrays A[1, . . . , m] and B[1, . . . , n], respectively.
Further, for integers i ∈ {1, . . . , m} and j ∈ {1, . . . , n}, let A[1, . . . , i] and B[1, . . . , j] be
the substrings formed by the first i characters of A and the first j characters of B, respectively.
We introduce LCS [i, j] to denote the length of a longest common sub-sequence of A[1, . . . , i]
and B[1, . . . , j]. Hence, LCS [i, j] is the length of the longest common sub-sequence of
A and B. We can define LCS [i, j] recursively as follows. For i = 0 and j = 0 (if we
consider two empty strings), LCS [i, j] = LCS [0, 0] is 0. We clearly more generally have
LCS [i, 0] = LCS [0, j] = 0 for all i and j. Otherwise, we need to consider the following
cases:
(1) Both A[1, . . . , i] and B[1, . . . , j] end in the same character (i.e., A[i] = B[j]). In that
case, the longest common sub-sequence of A[1, . . . , i] and B[1, . . . , j] ends in A[i] =
B[j] and therefore,
∀i, j > 0 : A[i] = B[j] ⇒ LCS[i, j] = LCS[i − 1, j − 1] + 1.
1
(2) If A[i] 6= B[j], a common sub-sequence can end in at most one of the two (different)
characters A[i] and B[j] and thus,
∀i, j > 0 : A[i] 6= B[j] ⇒ LCS[i, j] = max{LCS[i, j − 1], LCS[i − 1, j]}.
To compute LCS [m, n], we set up an (n + 1) × (m + 1)-matrix, where LCS [i, j] is stored
in column i and row j. For each matrix element, we only need to consider at most 2 other
elements and we can therefore fill the whole matrix in time O(mn). The details are given in
Algorithm 1.
Input: Two sequences A[1, · · · , n] and B[1, · · · , m]
Output: The matrix LCS with m + 1 rows and n + 1 columns such that LCS[m, n]
returns the length of the longest common sub-sequence of A and B
for i ← 1 to n do
LCS[0, i] = 0;
end
for i ← 1 to m do
LCS[i, 0] = 0;
end
for i ← 1 to m do
for j ← 1 to n do
if A[j] = B[i] then
LCS[i, j] = LCS[i − 1, j − 1] + 1;
else
LCS[i, j] = max{LCS[i − 1, j], LCS[i, j − 1]};
end
end
end
return LCS[m, n];
Algorithm 1: Algorithm for the length of a longest common sub-sequence for A and B
(b) As shown in Figure 1, the first column and the first row are filled with zeroes, because
when an empty sequence is compared with a non-empty sequence, the length of the longest
common sub-sequence is zero.
Generally for all 1 ≤ i, j ≤ 8, if A[i] = B[j], LCS[i, j] is computed as LCS[i − 1, j − 1] + 1.
In Figure 1 this is indicated by a diagonal arrow &. If A[i] 6= B[j] and if LCS[i − 1, j] >
LCS[i, j − 1] (resp. LCS[i − 1, j] < LCS[i, j − 1]), the value LCS[i, j] is determined as
LCS[i−1, j] (resp. LCS[i, j−1]), which is depicted by a vertical arrow ↓ (resp. by a horizontal
arrow →). If A[i] 6= B[j] and LCS[i − 1, j] = LCS[i, j − 1], both values LCS[i − 1, j] and
LCS[i, j − 1] could be used to determine LCS[i, j] and therefore both arrows are added in
Figure 1. The length of the longest common sub-sequence of the two strings is LCS[8, 8] = 5.
To find the longest common sub-sequence of A and B, we just traverse the arrows backwards
through matrix starting in cell LCS[8, 8]. If there is a diagonal arrow pointing to the current
cell (the green dashed arrows in Figure 1), one move diagonally the the upper left neighbor
and returns the corresponding character. Otherwise, there is a vertical or horizontal arrow
(or even both) which point to the current cell. We just move to a cell from which there is
an arrow to the current cell and continue from there. The procedure outputs the characters
2
Ø
Ø 0
a
0
e
0
a
0
a
0
g
0
s
0
s
0
t
0
b 0
0
0
0
0
0
0
0
0
a 0
1
1
1
1
1
1
1
1
e 0
1
2
2
2
2
2
2
2
b 0
1
2
2
2
2
2
2
2
s 0
1
2
2
2
2
3
3
3
a 0
1
2
3
3
3
3
3
3
g 0
1
2
3
3
4
4
4
4
t 0
1
2
3
3
4
4
4
5
Figure 1: LCS Example.
of the LCS in reverse order. In Figure 1, the green arrows indicate these backward moves to
find the longest common sub-sequence.
(c) The shortest common super-sequence (SCS) problem of two sequences A and B is essentially equivalent to the LCS problem of A and B. From a common super-sequence C of
length ` ≥ max {m, n}, we get a common sub-sequence S of length at least m + n − `
as follows. Both sequences A and B appear as sub-sequences of C. Because C has only
length `, the two sub-sequences intersect in at least m + n − ` places and we therefore have
a common sub-sequence of that length. On the other hand, from a common sub-sequence of
length h, we get a common super-sequence of length m + n − h in an obvious way. To find
the shortest common super-sequence (SCS) of A and B, we execute the following steps:
(1) Compute a LCS of A and B by using the algorithm described in Parts (a) and (b).
(2) Move backwards along the (green) arrows as in (b). Whenever, we move on a horizontal
arrow, we add the corresponding character of A, whenever we move on a vertical arrow,
we add the corresponding symbol of B. If we move on a diagonal arrow, A and B have
the same character at the current position (the position from which we move). We then
add this symbol to the common super-sequence. As before, we get the SCS in reverse
order.
Exercise 2: Sharing an Inheritance
Assume that Alice and Bob are two siblings who inherit some goods from their deceased parents.
In order to share the inherited goods in a fair way, Alice and Bob decide about a value vi for each
inherited item i and they would like to share the goods so that both of them get items of the same
total value.
Assume that there are items 1, . . . , n and that each item i has an integer value vi > 0. Give a
dynamic programming algorithm that determines whether the n items can be partitioned into two
3
parts of equal total value. If the items can be partitioned like this, the algorithm should also allow
to compute such a partition. What is the time complexity of your algorithm? What assumptions
do you need to get an algorithm that runs in time polynomial in the total number of items n?
Solution: This problem can be solved by reduction to the knapsack problem. First, some initializations are needed so that the problem can be formulated as a knapsack instance. For each item
1 ≤ i ≤ n, we P
set the weight of item i equal to the corresponding value, i.e. wi := vi . We also
define V := 12 ni=1 wi . Note that to get a fair sharing, V has to be an integer (the total value
of all items has to be even). Otherwise, such a fair sharing is not possible. Then, we solve the
knapsack problem for n items and capacity V . If the total value of the optimal knapsack solution
is less than V , there is no fair way to share the items. Otherwise, the optimal knapsack solution
has value V , it corresponds to one side of the partition into two equal parts.
Input: A group of items with their values
Output: The possibility of sharing the items into two sets with equal total values
for i ← 1 to n do
wi := vi ;
end
P
V := 12 ni=1 wi ;
if V ∈
/ N then
return No
end
if Knapsack(n,V) < V then
return No
else
return Yes
end
Algorithm 2: Sharing an Inheritance
All the computations take O(n) time except for solving the knapsack instance which takes time
O(nV ) as we saw in the lecture. To get a running time that is polynomial in the number of items
n, we have to assume that all values are integers that are polynomially bounded in n.
Exercise 3: Stacking Boxes
We are given a set of n rectangular 3-D boxes, where the ith box has length `i , width wi , and
height hi , and where all three dimensions are positive integers. We further assume that for each
box i, `i ≥ wi . The objective is to create a stack of boxes which has a total volume that is as
large as possible, but one is only allowed to stack a box on top of another box if the dimensions
of the 2-D base of the lower box are each strictly larger than those of the 2-D base of the higher
box. Hence, it is only possible to put box j on top of box i if `i > `j and wi > wj . See Figure 2
as an illustration.
(a) As a first attempt, we might try to use a greedy algorithm. Because when stacking boxes on
top of each other, the lengths have to be strictly decreasing, a natural strategy might be to
first sort the boxes by decreasing length such that `1 ≥ `2 ≥ · · · ≥ `n . Then, we go through
the boxes in that order and add a box on the existing stack whenever possible. Show that the
behavior of this greedy algorithm can be arbitrarily bad!
4
(b) Instead of sorting the boxes by length, we could alternatively sort by decreasing area of the
2-D base. That is, we sort the boxes such that `1 w1 ≥ `2 w2 ≥ · · · ≥ `n wn . Show that
now, box j can only be placed on top of box i if j > i and therefore `j wj ≤ `i wi . We
again consider the greedy algorithm, but this time we go through the boxes according to the
new ordering where the boxes are sorted by decreasing base area. We further simplify and
assume that all boxes have height hi = 1. Show that if there is a stack of volume V , the
greedy algorithm finds a stack of volume at least Ω(V 2/3 ).
(c) As a greedy algorithm does not seem to lead to a solution of the problem, let us finally try
another approach. We again consider the general case where the heights of the boxes are
arbitrary integers. Give an efficient algorithm that solves the box stacking problem by using
dynamic programming. (The algorithm should return a maximum volume stack of boxes.)
What is the running time of your algorithm? (as a function of n)
Hint: It might still make sense to go through the boxes in order of decreasing base area.
Remark: This was an exam question in Fall 2013.
𝑤
ℓ𝓁 ≥ 𝑤
ℎ
ℎ
ℓ𝓁 ≥ 𝑤
𝑤
ℎ
𝑤
ℎ
ℓ𝓁 ≥ 𝑤
ℎ
ℓ𝓁 ≥ 𝑤
𝑤
𝑤
ℓ𝓁 ≥ 𝑤
Figure 2: A single box of length `i , width wi , and height hi , as well as a feasible stack of boxes.
Solution:
(a) Here is a simple bad example to show that the suggested greedy algorithm can behave arbitrarily bad. Assume that we have only two boxes, one has length `, width 1, and height 1.
The second box has length ` − 1, width ` − 1, and height h 1. The greedy algorithm only
takes the first box, resulting in a total volume of `. An optimal algorithm takes the second
box and gets a volume of (` − 1)2 · h. By choosing h sufficiently large, the ratio between the
two solutions can be made arbitrarily large.
(b) According to the assumptions, generally for any two boxes i and j, box j can only be placed
on top of box i if `i > `j and wi > wj . Because the boxes are sorted by base area, if j < i,
`j wj ≥ `i wi and therefore either `j ≥ `i or wj ≥ wi . Box j can thus not be place on top of
box i.
Let us now come to the suggested greedy algorithm and recall that the boxes are sorted
by decreasing base area such that `1 w1 ≥ · · · ≥ `n wn . We define Ai := `i wi to be the base
area of box i. Note that from hi = 1, it follows that the volume of box i is also equal to Ai .
The greedy algorithm takes at least box 1 and therefore obtains a stack of volume at least A1 .
Consider an optimal solution and assume that box i is part of that solution. The base area
5
of box i is Ai and thus its volume is Ai ≤ A1 . Further,
√ because all boxes have base area at
. Because widths are assumed to be
most A1 and because wi ≤ `i , for each box i, wi ≤ A1√
integers, any feasible stack therefore has height at most A1 (to stack boxes on top of each
other, the lengths and the widths have to be strictly decreasing). The total volume V of any
√
3/2
feasible stack is therefore at most V ≤ A1 · A1 = A1 . The volume of the greedy solution
therefore is at least A1 ≥ V 2/3 .
(c) To get an efficient dynamic programming algorithm we need to find a recursive definition of
the problem. We follow the hint and assume that the boxes are sorted in non-increasing order
of their base areas (this preparation step takes O(n log n) time). We define V (i) to be the
maximum volume of a feasible stack of boxes where box i is the box on top. We can write
V (i) recursively as follows,
V (i) =
max
j<i:`j >`i ,wj >wi
{V (j)} + `i wi hi .
(1)
The optimal subproblems considered in our computation therefore are the optimal stacks of
boxes if a specific box is required to be on top. Note that in an optimal solution, potentially
every box can be the one at the top. At the end, the optimal solution to the problem can be
determined by taking the maximum over all the values V (i) for i ∈ {1, . . . , n}:
max
{V (i)}.
i∈{1,2,··· ,n}
Overall, The algorithm requires time O(n2 ) because to determine V (i), we potentially have
to check the values of i − 1 ≤ n other values V (j) (for j < i). An optimal stack (rather than
just the volume of an optimal stack) can be obtained by remembering for each box i, on top
of which other box it has to be placed to get an optimal stack with box i as the top box. That
is, for each V (i), we store, which value j < i maximizes the recursive rule in (1).
6