CSci 231 Homework 7 Solutions - Bowdoin College
CSci 231 Homework 7 Solutions - Bowdoin College
CSci 231 Homework 7 Solutions - Bowdoin College
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>CSci</strong> <strong>231</strong> <strong>Homework</strong> 7 <strong>Solutions</strong> ∗<br />
Dynamic Programming and Greedy Algorithms<br />
CLRS Chapter 15 and 16<br />
Use a (single) separate sheet of paper for each problem. Be concise.<br />
1. A game-board consists of a row of n fields, each consisting of two numbers. The first<br />
number can be any positive integer, while the second is 1, 2, or 3. An example of a<br />
board with n = 6 could be the following:<br />
17 2 100 87 33 14<br />
1 2 3 1 1 1<br />
The object of the game is to jump from the first to the last field in the row. The top<br />
number of a field is the cost of visiting that field. The bottom number is the maximal<br />
number of fields one is allowed to jump to the right from the field. The cost of a game<br />
is the sum of the costs of the visited fields.<br />
Let the board be represented in a two-dimensional array B[n, 2]. The following recursive<br />
procedure (when called with argument 1) computes the cost of the cheapest<br />
game:<br />
Cheap(i)<br />
END Cheap<br />
IF i>n THEN return 0<br />
x=B[i,1]+Cheap(i+1)<br />
y=B[i,1]+Cheap(i+2)<br />
z=B[i,1]+Cheap(i+3)<br />
IF B[i,2]=1 THEN return x<br />
IF B[i,2]=2 THEN return min(x,y)<br />
IF B[i,2]=3 THEN return min(x,y,z)<br />
∗ Collaboration is allowed and encouraged, if it is constructive and helps you study better. Remember,<br />
exams will be individual. List the names of the collaborators with the solutions.
(a) Analyze the asymptotic running time of the procedure.<br />
Solution:<br />
T (n) = T (n − 1) + T (n − 2) + T (n − 3) + Θ(1)<br />
≥ 3 T (n − 3)<br />
= 3 2 T (n − 6)<br />
= . . .<br />
= 3 k T (n − 3k)<br />
≥ 3 n/3<br />
= Ω(3 n/3 ).<br />
(b) Describe and analyze a more efficient algorithm for finding the cheapest game.<br />
Solution: We create a table T of size n in which to store our results of prior<br />
runs. The modified algorithm would be as follows:<br />
Cheap(i)<br />
END Cheap<br />
IF T[i] != ∅ THEN return T[i]<br />
IF i>n THEN return 0<br />
x=B[i,1]+Cheap(i+1)<br />
y=B[i,1]+Cheap(i+2)<br />
z=B[i,1]+Cheap(i+3)<br />
IF B[i,2]=1 THEN T[i] = x<br />
IF B[i,2]=2 THEN T[i] = min(x,y)<br />
IF B[i,2]=3 THEN T[i] = min(x,y,z)<br />
return T[i]<br />
The cost of a recursive call is O(1) and we fill each entry in the table at most<br />
once, so the running time is O(n).<br />
2
2. In this problem we consider the 0-1 knapsack problem: Given n items, with item<br />
i being worth v[i] dollars and having weight w[i] pounds, fill a knapsack of capacity m<br />
pounds with the maximal possible value.<br />
Example: Given a knapsack of capacity 50, the maximal value obtainable<br />
with three items of value $60, $100, and $120 and weights 10, 20, and 30,<br />
respectively, is $220.<br />
$60<br />
10<br />
$100<br />
20<br />
Items in value<br />
per pound<br />
order<br />
$120<br />
30<br />
30<br />
20<br />
= $220<br />
Optimal solution<br />
for knapsack of<br />
size 50<br />
20<br />
10<br />
= $160<br />
Greedy solution<br />
for knapsack of<br />
size 50<br />
The algorithm Knapsack(i,j) below returns the maximal value obtainable when filling<br />
a knapsack of capacity j using items among items 1 through i (Knapsack(n,m)<br />
solves our problem). The algorithm works by recursively computing the best solution<br />
obtainable with the last item and the best solution obtainable without the last item,<br />
and returning the best of them.<br />
Knapsack(i,j)<br />
IF w[i]
Solution:<br />
(a) Following the hint, if w[i] = 1 then it is clear that T (n, m) > 2T (n − 1, m −<br />
1) + 1. This recurrence, which runs for min(m, n) steps, gives that T (n, m) =<br />
Ω(2 min(m,n) ).<br />
(b) We create a table of size [n][m] in which to store our results of prior runs. The<br />
modified algorithm would be as follows:<br />
Knapsack(i,j)<br />
END<br />
IF table[i][j] != 0 THEN<br />
RETURN table[i][j]<br />
IF w[i]
3. Imagine now that the items in the problem above are such that you can take fractions<br />
of items. With this modified condition, the problem is called the Fractional<br />
Knapsack problem. Identify a greedy strategy to solve the problem. Prove that<br />
this strategy correctly identifies an optimal solution for all possible inputs.<br />
Analyse the running time of your algorithm and compare it with the 0-1 knapsack<br />
problem running time.<br />
Does it pay off being greedy (in this case)?<br />
Solution: Let v[i] and w[i] denote the weight and value of item i, respectively.<br />
Compute for each item the price per pound vp[i] = v[i]/w[i].<br />
Sort the items in decreasing order of their vp[i]. For simplicity renumber the elements<br />
so that the first item is the one with the largerst vp and so on.<br />
The choice that the thief has to make is which item to include in the knapsack. Being<br />
a thief it is very tempting to be greedy, and go for the big buck first. Here is the<br />
algorithm:<br />
FR-Knapsack(i, w)<br />
//returns the maximum value obtainable when filling a<br />
//knapsack of capacity $w$ with using items $i$ through $n$.<br />
IF i > n RETURN 0<br />
IF w[i] S, and<br />
therefore we get a contradiction. Thus we have proven that the first item is always<br />
part of an optimal solution.<br />
The rest of the correctness proof follows by induction on i. The algorithm is trivially<br />
true when i = n. Let S1n be the optimal solution FR-KNAPSACK(1, w) and let S2n<br />
5
e the optimal solution for FR-KNAPSACK(2, w-w[1]). By induction hypothesis<br />
we assume that S2n is computed correctly by FR-KNAPSACK(2, w-w[1]). We<br />
know that the first item is part of S1n, and let the remaining part of S1n be called S ′ :<br />
S1n = v[1] + S ′ . S ′ contains items 2 through n and therefore S ′ is at most the optimal<br />
solution S2n: S ′ ≤ S2n.<br />
Then S ′ = S2n, otherwise we could replace S ′ with S2n in S1n and get a solution<br />
v[1] + S2n > v[1] + S ′ = S1n, contradiction. Thus v[1] + S2n is the optimal solution for<br />
FR-KNAPSACK(1, w).<br />
6
4. Suppose you are in charge of planning a party for <strong>Bowdoin</strong> <strong>College</strong>. The college has<br />
a hierarchical structure, which forms a tree rooted at President Mills. On the very<br />
last level are the faculty, grouped by department. (I have such a chart in my office, if<br />
you need to be visual). Each faculty has “underneath” all students taking a class with<br />
him/her that particular semester. Assume that every person is listed at the highest<br />
possible position in the tree and there are no double affiliations (everybody has one<br />
and only one supervisor in this hierarchy and no student is in more than one class).<br />
You have access to a secret database which ranks each faculty/staff/student with a<br />
conviviality rating (a real number, which can be negative if the person is really difficult<br />
or boring). In order to make the party fun for everybody, President Mills does not<br />
want both a faculty/staff/student and his or her immediate “supervisor” to attend.<br />
You are given a tree that describes the strucure of <strong>Bowdoin</strong> <strong>College</strong>. Each node has<br />
a (down) pointer to its left-most child, and a (right) pointer to its next sibling (if<br />
unclear read Section 10.4 in CLR). Each node also holds a name and a conviviality<br />
ranking. Describe an algorithm to make up a guest list that maximizes the sum of the<br />
conviviality rankings of the guests. Analyze the running time of your algorithm.<br />
Solution: Let x be a node in the tree.<br />
Let PartyMix(x) return the optimal conviviality rating obtainable from the subtree<br />
rooted at x.<br />
We want to compute PartyMix(President Mills).<br />
Here is the recursive formulation of PartyMix(x):<br />
Let ch(x) be the list of children of x.<br />
Let grc(x) be the list of grandchildren of x.<br />
PartyMix(x) = 0 if x == NULL<br />
PartyMix(x) = max {conv(x) + <br />
y∈grc(x) P artyMix(y), <br />
z∈ch(x) P artyMix(z)}<br />
To make this approach efficient, we keep a table with T [x] storing the solution of<br />
PartyMix(x). Initially all entries in the table are set to −∞.<br />
Analysis: The table has n entries. Assume that these entries are computed in bottomup<br />
order so that we can ignore the recursion costs. An entry x is computed in<br />
O(|ch(x)|+|gr(x)|) time. Thus to compute all entries it takes <br />
x |ch(x)|+|gr(x)| time.<br />
A node can only be child to a single node, so it is counted only once in <br />
x |ch(x)|.<br />
Similarly a node can be grandchild to a single node, so it is counted only once in<br />
<br />
x |gc(x)|. Thus <br />
x |ch(x)| + |gr(x)| is O(n). Therefore the algorithm takes O(n)<br />
time.<br />
7