You are on page 1of 13

Design and Analysis of Algorithms D, E, F

FAST-NU, Lahore, Spring 2020

Homework 2

Dynamic Programming + Graphs

Partial Solutions

400 pts

PART I
In this homework, you will be asked to code in C++ from time to time. C++ codes are not
to be submitted, but you will provide their outputs on the given inputs. Wherever you’re
asked to provide pseudo-codes, you must provide them in your hard-copy submissions.
Problem 1 “Re-visiting the LIS: Longest Increasing Sub-sequence problem”
Recall the DP algorithm for the LIS problem. The algorithm used the following recurrence:
LIS[i] = max {LIS[j] + 1}
+,-./ 123 4[-].4[/]

In addition to the LIS array, we also maintained an array called prev to store the actual
sequences. Refer to your notes to see how we did that.
(i) In class, we coded this recurrence using bottom-up DP. Here, provide pseudo-
code for the top-down DP algorithm.

LIS(A, i, lis)

IF(lis[i] == -1){
bestSoFar<—1
FOR j <— i-1 to 1
{
IF(A[j] < A[i]){
sublen <— LIS(j)
IF(sublen +1 > bestSoFar)
{
bestSoFar <— sublen + 1
}
}
}
lis[i] ß bestSoFar
return lis[i]
}
ELSE
{
return lis[i]
}
}

(ii) Convert your pseudo-code in (i) into C++ code. Run the code on the files
“lis_input1.csv” and “lis_input2.csv”, and report the last 10 numbers of the LIS
in both cases, plus, the lengths of these LIS.

Discuss if needed.
It is possible that the input has more than one LIS. Our current algorithm reports any one
of them. However, we’re interested in knowing how many unique LIS exist in the input.
(iii) Give a modified version of the bottom-up algorithm written in class that reports
the number of unique LIS in the input. Note: it doesn’t return all these LIS,
simply, reports how many of them are there. It should take no more than O(n2)
time. Give pseudo-code.

Informal summary:
Keep an array called Count. While computing lis[i], if, for example, lis[j]+1 and
lis[k]+1 both give optimal lengths (where both j<i and k<i), then Count[i] =
Count[j] + Count[k].
In general there could be more than two sub-problems that can be extended
to yield the same optimal. In that case, use a loop to sum all those counts:
+
count[i] = ? -A/B+ Count[j]
C/D[-]E+ /D FGH/I1C

In the end, in a single loop, add the counts at each index i that gives the max
sequence length overall.

(iv) To your answers of (ii), also add the number of unique LIS in the two input files.
Again, no need to submit the code, simply report the outputs.
Discuss if needed.
(v) Our requirements have changed a bit. We now wish to compute the longest-
most-odd increasing subsequence (LmoIS). This is an LIS that has the greatest
number of odd numbers among all the LIS in the input. For example, if an input
had 1 3 4 8, and 2 3 7 9 both as LIS, our algorithm will report 2 3 7 9 since it
has more odd numbers in it. Provide the pseudo-code for this algorithm. It
should take no more than O(n2) time.
Informal summary:
Keep an array called odd_count. Originally, set odd_count[i] = 0 for all i. Set
odd_count[1] = 1 if A[1] is odd and 0 otherwise.
Each time while extending a sequence at lis[i] using lis[j], set odd_count[i] =
odd_count[j]+1 if A[i] is odd, and simply set odd_count[i] = odd_count[j] if A[i] is
even. Also, if there are multiple lis[j] that give the same optimal answer lis[i],
choose the one that yields the highest odd_count[i] value.

(vi) To your answers of (ii) and (iv) also add the last 10 numbers of the LmoIS
(Note: there may exist more than one LmoIS, and you may report the last 10
numbers of any one of them).
Discuss if needed.

Problem 2 “The Strange Room”


You have a strange room in your house and a strange set of mats to cover its floor with.
The room has dimensions 2 x k sq. feet, and each mat is a rectangle of exactly 2 sq. feet.
Following pictures explain the situation:

A 2 sq. feet mat may be placed horizontally or vertically as shown below. Note: the colors
in the following pictures are only there to show you the orientations of the mats. All mats
are identical in reality, having the same color.

A mat placed horizontally A mat placed vertically


There is only one way to mat this floor,
a 2x1 floor and that is:

There are two ways to mat this floor, and


a 2x2 floor they are:

Can you see that there are 3 ways to cover a 2x3 floor?

How many ways are there to cover a 2x4 floor?

Write a DP algorithm to count the number of ways there are to mat a 2 x n sq. feet floor.
Give a recurrence. Write a bottom-up pseudo-code. Implement the code in C++ and
report the count for: n = 10, 20 and 30.

Informal Summary:
Imagine we are laying out the mats one by one, left to right. If k-1 mats have already
been laid out, then how many different ways are there of lay the kth mat?
i) The kth mat can either be laid vertically (in which case the previous k-1 mats
stay as such.)
ii) The kth mat can be added horizontally, above or below the (k-1)th mat. In
which case the previous k-2 mats stay as such.
Note: in this case, it doesn’t matter if the kth mat is above or below the k-1th
mat: both count as a single arrangement as the mats are indistinguishable.

Therefore, count_ways[k] = count_ways[k-1] + count_ways[k-2]

Problem 3 “The Strange Highway”

The semester is over! You’ve rented a car and are ready to set out on a long drive on
the Strange Highway. There are 𝑛 tourist stores on the Strange Highway, numbered 1,
2, …, 𝑛 and you would want to stop at these and buy some souvenirs (only one
souvenir may be bought from a store and all souvenirs everywhere have the same
price). You are a greedy shopper and are most interested in maximizing the total
discount you get on your shoppings. You know that each store 𝑖 offers a discount 𝑑O on
a souvenir. But it’s a strange highway after all. It turns out that you can only buy a
souvenir from a store 𝑖 if you have not bought anything from the previous 𝑓O stores. For
example, if 𝑓Q = 3 then you can only buy a souvenir from store 6, and get the discount
𝑑Q , if you haven’t bought anything from stores 3, 4, and 5. All the 𝑑O and 𝑓O are known to
you in advance (passed as input). You have recently learnt the DP technique in your
algorithms course and wish to apply it here in order to maximize your total discount
under the given constraints.

(i) I will help you by defining the optimal sub-structure. In fact, I will give you two
possible definitions:

A. 𝐷[𝑖 ] = max total discount when store 𝑖 is the last store where you buy a souvenir.
B. 𝐷[𝑖 ] = max total discount for the trip till store 𝑖 whether buying at store 𝑖 or not.

Provide recurrences for D[i] in both cases A and B. Do both these


recurrences produce equally efficient algorithms?

Recurrences:
A. 𝐷[𝑖 ] = max total discount when store 𝑖 is the last store where you buy a souvenir.
𝐷 [𝑖 ] = max {𝐷 [𝑘] + 𝑑O }
+.T.(OBVW )
B. 𝐷[𝑖 ] = max total discount for the trip till store 𝑖 whether buying at store 𝑖 or not.
𝐷 [𝑖 ] = max (𝐷[𝑖 − 𝑓O − 1] + 𝑑O , 𝐷[𝑖 − 1])

Option (B) results in a better, O(n) algorithm. Option (A) results in an O(n2)
algorithm.

Ask questions on the group if you need further clarity.

(ii) Provide complete pseudo-code of the bottom-up DP algorithm based on one of


the recurrences above. The algorithm should return the optimal total discount
as well as the list of stores where to buy the souvenirs to get that discount.

Discuss if needed
PART II

Problem 4 “k heads in n tosses” (classwork problem)


You have n coins to toss. Each coin has a different probability of turning up heads or tails.
Specifically, the probability that the ith coin will turn up heads is pi (so the probability that it
will turn up tails is 1- pi. If all the coins were ‘fair’, then each pi would be 1/2; however, the
coins are not necessarily fair so pi can be any real number in the interval [0, 1]. You need
to compute the probability that when these n coins are tossed one after the other, any k
of them will turn up heads.

(a) Give the following sub-structure definition, write down the recurrence to compute
it. Also list all the base cases.

P[n, k] = probability that k out of n tosses turn up heads.

We did this in class, so I will not explain here:


P[n, k] = P[n-1, k-1] * pk + P[n-1, k] * (1-pk)

(b) Give pseudo-code for the iterative (bottom-up) algorithm to compute P[n, k]. Also
show the structure of the matrix P, which should be an O(nk) sized matrix.
Discuss if needed.
(c) Compute P[12, 7], for the following list of probabilities. Just give us the final answer.

p1 0.57
p2 0.51
p3 0.29
p4 0.39
p5 0.31
p6 0.51
p7 0.55
p8 0.89
p9 0.99
p10 0.09
p11 0.01
p12 0.12
Discuss if needed.

(d) How can you change your code in (b) so that it now takes only O(k) space,
instead of O(nk)?

Keep only the last column instead of the while matrix.

Problem 5 “Rod cutting with a difference” (derived from a classwork problem)


Recall the rod cutting problem from class. You may read it again, in greater detail, from
your book, CLSR, page 360, or simply refer to the notes from class.

I modify the problem by changing the requirements of the cutting. We are now only
interested in cuttings in which every piece is of unique length: we may call such cuttings
non-repetitive. For example, for a road of length 8, the non-repetitive cuttings include:
1+7, 2+6, 3+5, 1+3+4, 1+2+5 etc. In short, there’s only one piece of a given length in
the cutting. Therefore, cuttings like 4+4, 2+3+3 etc, are not admissible.

We wish to compute the optimal non-repetitive cutting that maximizes the total revenue.
The input, like in the original problem, is a list of prices for each length.
(a) Define an optimal sub-structure for this problem.
(b) Define a recurrence for your optimal sub-structure in (a).
(c) Write a simple top-down recursive pseudo-code (without memoization) for your
recurrence in (b). How much time does this algorithm take, in terms of big-Oh?
(d) Can we use DP to speed up this problem? If yes, describe the sub-problem
matrix you’ll use to store sub-problem results, and the resulting running time. If
no, describe exactly why DP is not useful.

Informal summary:

DP is useless in this case as we need to save an exponential number of sub-


problems to re-use them. i.e. storing optimal answers for all combinations of choices so
that we don’t repeat a piece. This requirement of ‘remembering’ which piece was picked
makes it impossible to solve in polynomial time.

Problem 6 “The War of Zopita”

You were born during the 5th great war between the planets Earth and Zopita. Growing
up, you despised the atrocities of interplanetary-conflict and dreamt of universal peace.
After a long, long struggle – years of warfare (and a betrayal in love by a Zopita
sweetheart) – it all boiled down to you solving a computational problem to put the
wretched war to an end! This was what you had to do: Given an unbroken stream of
characters, transmitted from the Zopita Headquarters, you had to determine whether the
stream was a string (a sentence) of valid English words, or not. For example, the stream
“uuydhllhfis” does not give a string of valid words, but the stream,
“unleashdeadlyturtleheadsonearthplease”, is just the sentence: “unleash deadly
turtleheads on earth please”. To your aide you have a lexicon of concise 40th century
English. Given a string w, this lexicon returns true if w is a valid English word and false
otherwise in O(1). Given a stream of length n i.e. n characters, describe a DP algorithm
that will detect whether or not the input string is a valid English sentence. Your algorithm
should also print the valid string. Beware: the future of the Earth is in your hands!

• Define an optimal subproblem, E[k]


• Define a recurrence to compute subproblem E[k] using smaller subproblems.
• Define an array S[k] that can be used to retrieve a valid splitting of the war message
into words, if one exists.

𝐟𝐚𝐥𝐬𝐞, 𝐢𝐟 𝐧𝐨 𝐯𝐚𝐥𝐢𝐝 𝐬𝐞𝐧𝐭𝐞𝐧𝐜𝐞 𝐞𝐧𝐝𝐬 𝐚𝐭 𝐢𝐧𝐝𝐞𝐱 𝐤


𝐄[𝐤] = ]
𝐭𝐫𝐮𝐞 , 𝐢𝐟 𝐚 𝐯𝐚𝐥𝐢𝐝 𝐬𝐞𝐧𝐭𝐞𝐧𝐜𝐞 𝐞𝐧𝐝𝐬 𝐚𝐭 𝐢𝐧𝐝𝐞𝐱 𝐤

𝒌B𝟏

𝐄[𝐤] = n(𝑬[𝒊] ∧ 𝒍𝒆𝒙(𝒔[𝒊 + 𝟏 … 𝒌])


𝒊A𝟏

Set S[k] = i for whichever i E[k] is computed as true above.

Here the function lex returns true if the sub-string is a word and false otherwise, in O(1).
NOTE: V is the mathematical simple for OR-ing, and ∧ meaning and-ding.

Problem 7 “The Matrix Chain Multiplication, revisited” (This problem will be


covered in the first online class)

We studied this problem in class, and a full description of it is available in your book,
CLSR, page 370 onwards. Read the entire section 15.2 and answer the following
questions:

(a) Following is a recurrence derived in that article for the number of


parameterizations of a chain of size n.

Describe, in plain English, what this recurrence means.

If there are 5 ways to bracket a first-piece of length k and 10 ways to bracket the
remaining-piece of length (n-1), then, since, bracketing of both pieces is independent of
each other, the total number of ways would be 5*10 = 50. When we sum up these
products for all possible lengths of the first-piece and remaining-piece, we get the
recurrence of (15.6).
(b) Understand and Implement the algorithms Matrix-Chain-Order(p) and Print-
Optimal-Parens(s, i, j), given on pages 375 and 377 respectively. (Again, we
don’t need your codes).
Execute your codes on the following inputs and report the optimal bracketing in
each case:

Input 1:

d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10
15 5 10 2 6 11 10 6 5 9 4

Input 2:

d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10
1 2 7 11 16 3 7 5 4 11 21

Input 3:

d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10
10 12 16 3 2 5 11 18 16 12 10

Discuss if needed.

Optional Problem, you may solve the following problem for the sake of learning (I
highly recommend it), but it is not required in the solutions.

Problem 8 “The * operation”

The following table defines the * operation between three characters: x, y and z.

* x y z

x y y x

y z y x

z x z z

As input, your algorithm receives a sequence, composed of the characters x, y and


z. For example, yyyyxz. The program decides whether it is possible to bracket the
sequence in such a way that, the result of the overall operation comes out to be x. For
example, for the sequence given above, there exists the bracketing: ((y * (y*y)) * (y*x)) *
z = x, so in this case your algorithm should return true and also output the desired
bracketing. The algorithm should be as efficient as possible.

(a) Give the design, including pseudo-code for this DP algorithm (show the optimal
sub-structure, recurrence, and pseudo-code for bottom-up solution.)
PART III

The following question is quite simple. You may discuss the solutions with me if
needed.

Problem 8 “Dry Runs”

a) Perform depth-first search on the following graph; whenever there's a choice of


vertices, pick the one that is alphabetically first. Classify each edge as a tree
edge, forward edge, back edge, or cross edge, and give the pre and post
number of each vertex. Start from A.

b) Run the DFS-based topological ordering algorithm on the following graph.


Whenever you have a choice of vertices to explore, always pick the one that is
alphabetically first.

(i) Indicate the pre and post numbers of the nodes.


(ii) What are the sources and sinks of the graph?
(iii) What topological ordering is found by the algorithm?
(iv) How many topological orderings does this graph have?
c) Run the strongly connected components algorithm on the following directed
graph G . When doing DFS on GR : whenever there is a choice of vertices to
explore, always pick the one that is alphabetically first.

Answer the following questions:

(i) In what order are the strongly connected components (SCCs) found?
(ii) Which are source SCCs and which are sink SCCs?
(iii) Draw the metagraph (each meta-node is a SCC of G).
(iv) What is the minimum number of edges you must add to this graph to make
the whole of it a single strongly connected component?

d) Given below is a weighted directed graph G=(V, E, w). Obviously, we cannot find
its shortest paths using simple BFS. However, we will still execute BFS on it as
see the output.
i) Draw the BFS based SSSP tree for the following graph (assuming that
edges are unweighted). Take node A as source.

ii) Draw the actual (correct) SSSP tree for the above graph. I am not asking
you to run any algorithm. Simply inspect the graph manually and draw the
correct tree (multiple correct trees may be possible, just give one). Write
down the total shortest path distance with each node. Take A as source.

You might also like