Examens Eng PDF

Download as pdf or txt
Download as pdf or txt
You are on page 1of 250

DATA STRUCTURES AND ALGORITHMS

COLLECTION OF EXAMS

Albert Atserias
Amalia Duch
Enric Rodrı́guez Carbonell
(Editors)

January 28, 2019

Departament de Ciències de la Computació


Universitat Politècnica de Catalunya
Contents

1 Mid Term Exams 1

2 Lab Exams 73

3 Final Exams 81

4 Solutions to Mid Term Exams 159

5 Solutions to Lab Exams 177

6 Solutions to Final Exams 227


1
Mid Term Exams
2 Mid Term Exams

Midterm EDA Length: 2 hours 24/3/2014

Problem 1 (3 points)

As graphs, all trees are planar. In particular this means that they are all representable on a
sufficiently large rectangular grid in such a way that the edges do not intersect (except at the
vertices, obviously). Here are two planar representations of a full binary tree with 16 leaves:

(1 point) Following the recursive pattern of the first representation, give recurrences for
the height H (n) and width W (n), respectively, of the grid that is needed to represent a full
binary tree with 2n leaves in this representation.

✬ ✩

✫ ✪

(1 point) Following the recursive pattern of the second representation, give the recurrence
for the length L(n) of the square grid that is needed to represent a full binary tree with 4n
leaves in this representation.
Mid Term Exams 3

✬ ✩

✫ ✪
4n
(1 point) If your goal is to minimize the area of the grid for a full binary tree with leaves,
explain which of the two representations you will choose (to relate both representations note
that 4n = 22n ). You do not need to solve the recurrences exactly; an asymptotic estimation is
enough.
✬ ✩

✫ ✪

Problem 2 (2 points)
Consider the following four pieces of code:
void f1 (int n) { void f2 (int n) {
int x = 2; int x = 2;
int y = 1; int y = 1;
while (y ≤ n) { while (y ≤ n) {
y = y + x; y = y + x;
x = x + 1; x = 2*x;
} } } }

void f3 (int n) { void f4 (int n) {


int x = 2; int x = 2;
4 Mid Term Exams

int y = 1; int y = 1;
while (y ≤ n) { while (y ≤ n) {
y = y*x; y = y*x;
x = 2*x; x = x*x;
} } } }

✞ ☎
What is the cost of f 1? Answer: Θ( ✝
✞ ✆)

What is the cost of f 2? Answer: Θ( ✝
✞ ✆)

What is the cost of f 3? Answer: Θ( ✝
✞ ✆)

What is the cost of f 4? Answer: Θ( ✝ ✆)

A correct answer without proper reasoning will not get any points.


(0,5 points) Reasoning for f 1: ✩

✫ ✪


(0,5 points) Reasoning for f 2: ✩

✫ ✪
(0,5 points) Reasoning for f 3:
Mid Term Exams 5

✬ ✩

✫ ✪

(0,5 points) Reasoning for f 4: ✩

✫ ✪

Problem 3 (3 points)

An inversion in a vector of integers T [0 . . . n − 1] is a pair of positions storing values that are


not ordered, that is, a pair (i, j) such that 0 ≤ i < j < n and T [i ] > T [ j].

(1.5 points) Let T [0 . . . n − 1] be a vector of integers. Show that if there is an inversion (i, j) in
T, then T has at least j − i inversions.
6 Mid Term Exams

✬ ✩

✫ ✪

(1.5 points) Let us fix a value N such that N ≥ 0 (that is, N is a constant in this exercise). By
using Divide & Conquer, implement in C++ a function

bool search (int x, const vector<int>& T)

which, given an integer x and a vector of integers T of size n with at most N inversions,
determines if x is in T. The function should have worst-case cost Θ(log n). Show that indeed
it has this cost.

Hint: to solve question 2, use the fact from question 1. Besides, deal with subvectors of size
≤ 2N in the base case of the recursion, and with the rest of subvectors in the recursive case.
Mid Term Exams 7

✬ ✩

✫ ✪

Problem 4 (2 points)

✞ ☎
Four quickies:

1. Let f (n) = n log(cos(nπ ) + 4)). Then f (n) = Θ( ✝ ✆).


✞ ☎
2. Which is the last digit of 71024 written in decimal notation? Answer: ✝ ✆.


3. What is the recurrence for the cost of Strassen’s☎algorithm to multiply n × n matrices?
Answer T (n) = ✝ ✆.
4. An algorithm admits all 2n vectors of n bits as possible inputs. On 2n − 1 of these in-
puts the cost of the algorithm is Θ(n2 ), and on the remaining one the cost is Θ(n4 ).
Therefore, its worst-case cost is Θ(n4 ) and its best-case cost is Θ(n2 ). What is its
average-case cost when the input is chosen uniformly at random (so each input has
8 Mid Term Exams

probability 1/2n )? ✞ ☎
Answer: T (n) = Θ( ✝ ✆).

✬ for questions 1, 2 and 4 (reasoning for question 3 is not required):


Reasoning ✩

✫ ✪
Mid Term Exams 9

Midterm EDA Length: 2.5 hours 13/10/2014

Problem 1 (2 points)

(1 point) Prove that ∑ni=0 i3 = Θ(n4 ).

Hint: There are several ways to do it, one of them by proving O and Ω separately.

✬ ✩

✫ ✪


log n
(1 punt) Let f (n) = 2 and g(n) = n. Asymptotically, which one grows faster? Prove it.
10 Mid Term Exams

✬ ✩

✫ ✪

Problem 2 (3 points)

Consider the procedure mystery which takes as inputs a vector A and a positive integer k
such that all elements of A are between 0 and k, both included.
void mystery(const vector<int>& A, vector<int>& B, int k){
int n = A. size ();
vector<int> C(k+1, 0);
for (int j = 0; j < n; ++j) ++C[A[j]];
for (int i = 1; i ≤ k; ++i) C[i] += C[i−1];
B = vector<int>(n);
for (int j = n−1; j ≥ 0; −−j){
B[C[A[j]] − 1] = A[j ];
−−C[A[j]];
}
}
Mid Term Exams 11

(a) (1 point) What is the content of B at the end of the execution of mystery?

✬ ✩

✫ ✪

(b) (1 point) If n is the length of the vector A and you are guaranteed that k = O(n), what is
the asymptotic cost of mystery as a function of n?

✬ ✩

✫ ✪

(c) (1 point) Without writing any code, describe an algorithm for the following problem:
given a positive integer k, a vector A of n integers between 0 and k, both endpoints included,
and a vector P of m pairs of integers ( a0 , b0 ), . . . , ( am−1 , bm−1 ), with 0 ≤ ai ≤ bi ≤ k for each
i = 0, . . . , m − 1, you are asked to write the number of elements of A which are in the interval
[ai , bi ] for i = 0, . . . , m − 1 in time Θ(m + n + k), and in particular time Θ(m + n) when k =
O ( n ).

Hint: using a vector C like the one in mystery will be useful.


12 Mid Term Exams

✬ ✩

✫ ✪

Problem 3 (3 points)
A board game of chance has 64 possible positions 1, . . . , 64. The rules of the game are such
that, from any position i ∈ {1, . . . , 64}, in one step a checker will hop to any other position
j ∈ {1, . . . , 64} with probability Pi,j . Let P = ( Pi,j )1≤i,j≤64 be this matrix of probabilities.

(a) (1 point) Remember that if R = P2 , then Ri,j = ∑64k=1 Pi,k Pk,j for each i, j. Taking into account

✤ ✜
that Pi,j is the probability of hopping from i to j in one step, how do you interpret Ri,j ?

✣ ✢
(b) (2 points) Design an algorithm that, given a matrix of probabilities P = ( Pi,j )1≤i,j≤64 and
given a certain number of steps t ≥ 0, computes the matrix ( Qi,j )1≤i,j≤64 where each Qi,j is
the probability that the checker, starting at position i, ends at position j after exactly t steps.
typedef vector<double> Row;
typedef vector<Row> Matrix;

void probabilities (const Matrix& P, int t , Matrix& Q) {


Mid Term Exams 13

✬ ✩

✫ ✪

Note 1: In order to get full grade your algorithm must run in Θ(log t) time.
Note 2: If you need any auxiliary function, implement on the back.
Note 3: Justify the cost of your algorithm on the back.

Auxiliary functions (if needed):


14 Mid Term Exams

✬ ✩

✫ ✪

Cost of the algorithm:

✬ ✩

✫ ✪
Mid Term Exams 15

Problem 4 (2 points)

(a) (1 point) Assume that an algorithm receives as input any of the 2n vectors of n bits with
equal probability. Assume that the worst-case cost of the algorithm is Θ(n2 ), and that its
best-case cost is Θ(n). How many inputs are required to cause cost Θ(n2 ) to be sure that the
average-case cost of the algorithm is Θ(n2 )?
✞ ☎
Answer: Ω( ✝ ✆)

Justification: ✩

✫ ✪

(b) (0.5 points) Consider the following algorithm that adds one unit to a natural number that
comes represented by a vector vector<int> A of n decimal digits:

int i = n − 1;
while (i ≥ 0 and A[i] == 9) { A[i] = 0; −−i; }
if ( i ≥ 0) ++A[i]; else cout << ``Overflow' ' << endl;

If every digit A[i] of the input is equally likely and independent of the rest (that is, each
A[i] is one of the 10 possible digits with probability 1/10 independently of the other digits),
what is the probability that this algorithm makes exactly k iterations when 0 ≤ k ≤ n − 1?
✞ ☎
Answer: ✝ ✆

Justification: ✩

✫ ✪

(c) (0.5 points) Use the master theorem for subtractive recurrences to solve the recurrencence
9
T (n) = 10 T (n − 1) + Θ(1) with base case T (0) = Θ(1).
✞ ☎
Answer: T (n) = Θ( ✝ ✆)
Justification:
16 Mid Term Exams

✬ ✩

✫ ✪
—————– END OF THE EXAM ——————-
(d) (optional extra bonus: 1 additional point to the grade) What does the recurrence T (n)

✬ ✩
from section (c) compute about the algorithm from section (b)?

✫ ✪
Mid Term Exams 17

Midterm EDA Length: 2h30m 23/3/2015

Problem 1: Cost analysis (2 points)

The sieve of Eratostenes (276–194 BC) is a method to generate all prime numbers smaller
or equal than a given n. The method goes as follows: traversing the sequence of num-
bers 2, 3, 4, . . . , n, look for the next number x that is not yet marked, mark all its multiples
2x, 3x, 4x, . . . up to n, and repeat with the next x. When it finishes, those x ≥ 2 that are not
marked are the prime numbers. In C++:

vector<bool> M(n + 1, false);


for (int x = 2; x ≤ n; ++x) {
if (not M[x]) {
for (int y = 2*x; y ≤ n; y += x) M[y] = true;
}
}

For the first three questions below we ask for an exact (non-asymptotic) expression as a
function of n. If needed, use the notation ⌊z⌋ that rounds z to the maximum integer smaller
or equal than z; for example, ⌊π ⌋ = ⌊3.14 . . . ⌋ = 3.

✞ many times☎
(a) (0.33 points) How is M[y] = true executed when x is 2?
Answer: Exactly ✝ ✆ many times.

✞ many times☎is M[y] = true executed when x is 15?


(b) (0.34 points) How
Answer: Exactly ✝ ✆ many times.

✞ many times ☎
(c) (0.33 points) How is M[y] = true executed when x is 17?
Answer: Exactly ✝ ✆ many times.

Note: More questions on the back.

(d) (0.5 points) It is known that

n
1
∑ p
= Θ(log log n).
p =2
p prime

Use this, in conjunction with the answers to the previous questions, to✞determine the cost☎of
the algorithm as a function of n, in asymptotic notation. Answer: Θ( ✝ ✆).

Justification:
18 Mid Term Exams

✬ ✩

✫ ✪

(e) (0.5 points) An improvement consists in replacing the condition x ≤ n in the external
loop by x*x ≤ n. Would this improve the asymptotic cost?

✬ and justification:
Answer ✩

✫ ✪

Problem 2: Strassen & company (2 points)

The school algorithm to multiply two n × n matrices makes Θ(n3 ) arithmetic operations. In
1969 Strassen found an algorithm that makes Θ(n2.81 ) arithmetic operations. Twenty one
years later, Coppersmith and Winograd discovered a method that makes Θ(n2.38 ) opera-
tions.

Assuming (for simplicity) that the implicit constants in the Θ notation are 1, 10 and 100,
respectively, and that they apply to every n ≥ 1 (that is, the costs are n3 , 10n2.81 and 100n2.38 ,
respectively, for every n ≥ 1), compute the least n for which one of these algorithms makes
less operations than another.
Mid Term Exams 19

✞ ☎
(a) (1 point) For n ≥ ✝ ✆, Strassen improves the school method.

✞ ☎
(b) (1 punt) For n ≥ ✝ ✆, Coppersmith-Winograd improves Strassen.


Justifications: ✩

✫ ✪

Problem 3: Algorithm design (3 points)

Given a sequence of n non-empty intervals [ a1 , b1 ], . . . , [ an , bn ], we want to compute their


union in time O(n log n). The output is represented by a sequence of disjoint intervals sorted
by their left boundary. For example, if the intervals in the input were [17, 19] [−3, 7] [4, 9] [18, 21] [−4, 15],
then the intervals in the output would be [−4, 15] [17, 21].

(a) (1 point) Describe an algorithm that solves this problem. Explain the algorithm in words,
without writing code, but clearly enough so that the algorithm can be implemented. Assume
that the input is given by the vectors ( a1 , . . . , an ) and (b1 , . . . , bn ), with ai ≤ bi for every i =
1, . . . , n.
20 Mid Term Exams

✬ ✩

✫ ✪

(b) (1 point) Now, in addition to the sequence of n intervals, we are given a sequence m
different reals p1 , . . . , pm , and we want to determine how many fall in some interval of the
union (only the number is needed; not which ones). Using the algorithm from the previous
section, describe an algorithm that solves this problem in time O(n log n) when m = n. As-
sume that the input is given by the vectors a and b from the previous section, and the vector
( p1 , . . . , pm ) with pi 6= p j if i 6= j.
Mid Term Exams 21

✬ ✩

✫ ✪

(c) (1 punt) If you happened to know that m is bounded by a small constant independent
of n, say m ≤ 5, would you still use the same algorithm? If not, which one would you use
instead? If you choose a different algorithm, make its cost explicit.
✬ ✩

✫ ✪

Problem 4: Quickies (3 points)

✞ ☎
• (0,5 points) Determine if they are equal (=) or different (6=), and prove it:

Θ(3log2 (n) ) ✝ ✆Θ(3log4 (n) ).


22 Mid Term Exams

✬ ✩

✫ ✪

• (0,5 points) Compute 21 · 22 · 23 · · · · · 299 · 2100 mod 9. This problem is not meant to be
solved with the help of a calculator.
✬ ✩

✫ ✪
• (1 point) Sort the functions that follow
√ increasingly according to their asymptotic
growth rates: n4 − 3n3 + 1, (ln(n))2 , n, n1/3 . Exceptionally, you are not required to
justify your answer.
✎ ☞

✍ ✌

• (1 point) Consider the following three alternatives for solving a problem:


– A: divide an instance of size n into five instances of size n/2, solve each instance
recursively, and combine the solutions in time Θ(n).
Mid Term Exams 23

– B: given an intance of size n, solve two instances of size n − 1 recursively, and


combine the solutions in constant time.
– C: divide an instance of size n into nine instances of size n/3, solve each instance
recursively, and combine the solutions in time Θ(n2 ).
Write down and solve the corresponding recurrences. Which alternative is the most

✬ ✩
efficient?

✫ ✪
24 Mid Term Exams

Midterm EDA Exam Length: 2.5 hours 19/10/2015

Problem 1 (3.5 points)

Fibonacci numbers are defined by the recurrence f k = f k−1 + f k−2 for k ≥ 2, with f 0 = 0 and
f1 = 1. Answer the following exercises:

(a) (0.5 points) Consider the following function fib1 which, given a non-negative integer k,
returns f k :

int fib1 (int k) {


vector<int> f(k+1);
f [0] = 0;
f [1] = 1;
for (int i = 2; i ≤ k; ++i)
f [ i ] = f [ i −1] + f [ i −2];
return f [k ];
}

Describe the asymptotic cost in time and space of fib1 (k) as a function of k as precisely as
possible.

✬ ✩

✫ ✪

(b) (1 point) Show that, for k ≥ 2, the following matrix identity holds:

  k−1  
1 1 fk f k−1
=
1 0 f k−1 f k−2
Mid Term Exams 25

✬ ✩

✫ ✪

(c) (1 point) Fill the gaps in the following code so that function fib2 (k) computes f k , given
a k ≥ 0.

typedef vector<vector<int>> matrix;

matrix mult(const matrix& A, const matrix& B) {


// Pre: A and B are square matrices of the same dimensions
int n = A. size ();
matrix C(n, vector<int>(n, 0));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
✞ ☎
for (int k = 0; k < n; ++k)

✝ ✆
return C;
}

matrix mystery(const matrix& M, int q) {


int s = M.size ();
if (q == 0) {
✞ ☎
matrix R(s, vector<int>(s, 0));
for (int i = 0; i < s; ++i) ✝ ✆
return R;
}
else {
✞ ☎
matrix P = mystery(M, q/2);
if ( ✝ ✆) return mult(P, P);
26 Mid Term Exams

✞ ☎
else return ✝ ✆;
} }

int fib2 (int k) {


if (k ≤ 1) return k;
matrix M = { {1, 1}, {1, 0} };
matrix P✞= mystery(M, k−1); ☎
return ✝ ✆;
}
(d) (1 point) Describe the asymptotic cost in time of fib2 (k) as a function of k as precisely as
possible.
✬ ✩

✫ ✪

Problem 2 (3.25 points)

Given a vector of integers v and an integer x, the function


int position (const vector<int>& v, int x) {
int n = v. size ();
for (int i = 0; i < n; ++i)
if (v[ i ] == x)
return i ;
return −1;
}

examines the n = v.size() positions of v and returns the first one that contains x, or −1 if
there is none.
Mid Term Exams 27

(a) (0.75 points) Describe as a function of n the asymptotic cost in time of position in the
best case as precisely as possible. When can this best case take place?

✬ ✩

✫ ✪

(b) (0.75 points) Describe as a function of n the asymptotic cost in time of position in the
worst case as precisely as possible. When can this worst case take place?

✬ ✩

✫ ✪

(c) (0.75 points) Show that for any integer n ≥ 1, the following identity holds:

n
i n 1
∑ 2i = 2 − 2n − 2n − 1 .
i=1
28 Mid Term Exams

✬ ✩

✫ ✪

(d) (1 point) Assume that we have a probability distribution over the input parameters.
Namely, the probability that x is element v[i ] is 2i1+1 for 0 ≤ i < n − 1, and that it is
element v[n − 1] is 2n1−1 . In particular, these probabilities add up 1, so that x is always
one of the n values of v.

Describe as a function of n the asymptotic cost in time of position in the average case as
precisely as possible.
Mid Term Exams 29

✬ ✩

✫ ✪

Problem 3 (3.25 points)

In this exercise we tackle the problem of, given two positive integers a and b, to compute
their greatest common divisor gcd( a, b). Recall that gcd( a, b) is, by definition, the only posi-
tive integer g such that:
1. g | a (g divides a),
2. g | b,
3. if d | a and d | b, then d | g.
(a) (1.25 points) Show that the following identities are true:

2 gcd( a/2, b/2)



 if a, b are even

gcd( a, b) = gcd( a, b/2) if a is odd and b is even
 gcd(( a − b)/2, b)

if a, b are odd and a > b
30 Mid Term Exams

Hint: you can use that, given two positive integers a and b such that a > b, we have
gcd( a, b) = gcd( a − b, b).

✬ ✩

✫ ✪

(b) (1 point) Write a function int gcd(int a, int b) in C++ which, by using divide and
conquer and exercise (a), computes the greatest common divisor gcd( a, b) of two given
positive integer numbers a, b.

Hint: you can also use that for any positive integer a, gcd( a, a) = a.
Mid Term Exams 31

✬ ✩

✫ ✪

(c) (1 point) Assuming that a and b are positive integers, each of which represented with a
vector of n bits, describe the cost in time in the worst case of gcd(a , b) as a function of n
as precisely as possible. When can this worst case take place?
Assume that the cost of the following operations with integers of n bits: adding, sub-
tracting, comparing, multiplying/dividing by 2 is Θ(n), and that computing the remain-
der modulo 2 takes time Θ(1).
✬ ✩

✫ ✪
32 Mid Term Exams

Midterm EDA Length: 2.5 hours 31/03/2016

Problem 1 (1 point)

Answer the following questions. In this exercise, you do not need to justify the answers.


1. (0.2 points) The☎cost of Strassen’s algorithm for multiplying two matrices of size n × n
is Θ( ✝ ✆)

2. (0.6 points) The master theorem for subtractive recurrences states that given a recur-
rence T (n) = aT (n − c) + Θ(nk ) with a, c > 0 and k ≥ 0 then:
 ✞ ☎
 ✝
✞ ✆ if a < 1,




✞ ✆

T (n) = if a = 1,
✝ ✆ if a > 1.


✞ ☎
3. (0.2 points) The mergesort sorting algorithm uses Θ( ✝ ✆) auxiliary space when
sorting a vector of size n.

Problem 2 (3 points)

In this problem costs are only considered in time. Consider the following program:

void f (int m);


void g(int m);

void h(int n) {
int p = 1;
for (int i = 1; i ≤ n; i++) {
f ( i );
if ( i == p) {
g(n );
p *= 2;
}} }

(a) (1.5 points) Answer: if the cost ✞


of f (m) as☎well as the cost of g(m) is Θ(m), then the cost
of h(n) as a function of n is Θ( ✝ ✆)

Justification:
Mid Term Exams 33

✬ ✩

✫ ✪

(b) (1.5 points) Answer: if the cost of f✞(m) is Θ(☎


1) and the cost of g(m) is Θ(m2 ), then the
cost of h(n) as a function of n is Θ( ✝ ✆)

Justification:
34 Mid Term Exams

✬ ✩

✫ ✪

Problem 3 (3 points)

We say that a square matrix M of integer numbers of size n × n is symmetric if Mi,j = M j,i for
all i, j such that 0 ≤ i, j < n.

Let us consider the following implementation of symmetric matrices with unidimensional


vectors, which only stores the “lower triangle” to minimise the consumed space:

 
M0,0 M0,1 M0,2 ... M0,n−1

 M1,0 M1,1 M1,2 ... M1,n−1 


 M2,0 M2,1 M2,2 ... M2,n−1 

 .. .. 
 . . 
Mn−1,0 Mn−1,1 Mn−1,2 . . . Mn−1,n−1

w
w
w


M0,0 M1,0 M1,1 M2,0 M2,1 M2,2 . . . Mn−1,0 Mn−1,1 Mn−1,2 . . . Mn−1,n−1

For example, the symmetric matrix 3 × 3


Mid Term Exams 35

 
1 2 0
 2 −2 3 
0 3 −1

would be implemented with the unidimensional vector

1 2 −2 0 3 −1

(a) (0.5 points) Answer: the✞ ☎ of this representation for a symmetric matrix n × n
cost in space
as a function of n is Θ( ✝ ✆).

Justification:
✬ ✩

✫ ✪
(b) (1 point) Given n > 0 and a value k, the function
pair <int,int> row column(int n, int k );
j is the column of the coefficient pointed by k in a unidimensional vector that implements
a symmetric matrix n × n. If k is not a valid index, it returns (−1, −1). For example,
row column(3,2) returns (1, 1), row column(3,3) returns (2, 0), and row column(3,6) returns
(−1, −1).


Complete the following implementation of row column:
int p(int x) { return ✂ ✁ ;}

int mystery(int k , int l , int r) {


if ( l+1 == r) return l;

int m = ( l+r)/2;
if (p(m) ≤ k) return mystery(k , ✂ ✄ ✁ , r);
else return mystery(k , l , ✂ ✁ );
}


pair <int,int> row column(int n, int k) {
if (k < 0 or k ≥ p(n)) return ✂ ✁;

int i = mystery(k, 0, n );
return {i , ✂ ✁ };
}
(c) (1 point) Analyse the cost in time in the worst case of the implementation of row column(int n, int k)
of the previous exercise as a function of n.
36 Mid Term Exams

✬ ✩

✫ ✪
functions double sqrt(double x) and int floor (double x) which
(d) (0.5 points) Using the √
respectively compute x and ⌊ x⌋ in time Θ(1), give an alternative implementation of
row column with cost Θ(1).
✬ ✩

✫ ✪

Problem 4 (3 points)
Assume that n is a power of 2, that is, of the form 2k for a certain k ≥ 0.

A square matrix A of real numbers of size n × n is a Monge matrix if for all i, j, k and l such
that 0 ≤ i < k < n and 0 ≤ j < l < n, it holds that

Ai,j + Ak,l ≤ Ai,l + Ak,j

In other words, whenever we take two rows and two columns of a Monge matrix and con-
sider the four elements at the intersections of the rows and the columns, the sum of the
elements at the upper left and lower right corners is less than or equal to the sum of the
elements at the upper right and lower left corners. For example, the following matrix is a
Monge matrix:

 
10 17 13 28
 16 22 16 29 
 
 24 28 22 34 
11 13 6 6
(a) (1 point) Let f A (i ) be the index of the column where the the minimum element of the
i-th row appears (breaking ties if needed by taking the leftmost one). For example, in
the matrix above f A (0) = 0, f A (1) = 0, f A (2) = 2 i f A (3) = 2.
Mid Term Exams 37

Show that f A (0) ≤ f A (1) ≤ . . . ≤ f A (n − 1) for any Monge matrix A of size n × n.

✬ ✩

✫ ✪

(b) (1 point) In what follows a divide-and-conquer algorithm is described which computes


the function f A for all rows of a Monge matrix A:

(1) Build two square submatrices B1 i B2 of the matrix A of sizes n2 × n2 as follows: B1


is formed by the rows of A with even index and the columns between 0 and n2 − 1,
and B2 is formed by the rows of A with even index and the columns between n2 and
n − 1.

(2) Recursively determine the column where the leftmost minimum appears for any
row of B1 and for any row of B2 .

(3) Find the column where the leftmost minimum appears for any row of A.

Explain how, by using the result of (2), one can accomplish (3) in time Θ(n).
38 Mid Term Exams

✬ ✩

✫ ✪

(c) (1 point) Compute the cost as a function of n of the algorithm proposed in the previous
exercise for computing the function f A for all rows of a Monge matrix A of size n × n.
Assume that step (1) can be carried out in time Θ(n).
✬ ✩

✫ ✪
Mid Term Exams 39

Midterm EDA exam Length: 2.5 hours 07/11/2016

Problem 1 (2 points)

In this problem you do not need to justify your answers.


(a) (0.8 pts.) Fill the gaps in the following table (except for the cell marked with Do not
fill) with the costs in time for sorting a vector of integers of size n using the indicated
algorithms. Assume uniform probability in the average case.
Best case Average case Worst case
Quicksort
(with Hoare’s partition)
Mergesort

Insertion Do not fill

✞ ☎
(b) (0.2 pts.) The solution to the recurrence T (n) = 2T (n/4) + Θ(1) is ✝ ✆
✞ ☎
(c) (0.2 pts.) The solution to the recurrence T (n) = 2T (n/4) + Θ( n) is ✝ ✆

✞ ☎
(d) (0.2 pts.) The solution to the recurrence T (n) = 2T (n/4) + Θ(n) is ✝ ✆

(e) (0.3 pts.) What does Karatsuba’s algorithm compute? What is its cost?
✬ ✩

✫ ✪
(f) (0.3 pts.) What does Strassen’s algorithm compute? What is its cost?
✬ ✩

✫ ✪
40 Mid Term Exams

Problem 2 (3 points)

Given n ≥ 2, we say that a sequence of n integers a0 , . . . , an−1 is bi-increasing if an−1 < a0 and
there exists an index t (with 0 ≤ t < n) that satisfies the following conditions:
• a0 ≤ . . . ≤ a t − 1 ≤ a t
• a t +1 ≤ a t +2 ≤ . . . ≤ a n −1

For example, the sequence 12, 12, 15, 20, 1, 3, 3, 5, 9 is bi-increasing (take t = 3).

(a) (2 pts.) Implement in C++ a function

bool search (const vector<int>& a, int x);

which, given a vector a that contains a bi-increasing sequence and an integer x, returns
whether x appears in the sequence or not. If you use auxiliary functions that are not part
of the C++ standard library, implement them too. The solution must have cost Θ(log(n))
in time in the worst case.
✬ ✩

✫ ✪
Mid Term Exams 41

(b) (1 pt.) Justify that the cost in time in the worst case of your function search is Θ(log(n)).
When does this worst case take place?
✬ ✩

✫ ✪

Problem 3 (2 points)

Consider the following function:


int mystery(int m, int n) {
int p = 1;
int x = m;
int y = n;
while (y 6= 0) {
if (y % 2 == 0) {
x *= x;
y /= 2;
}
else {
y −= 1;
p *= x;
} }
return p;
}
42 Mid Term Exams

(a) (1 pt.) Given two integers m, n ≥ 0, what does mystery(m,n) compute? You do not need
to justify your answer.
✬ ✩

✫ ✪

(b) (1 pt.) Analyse the cost in time in the worst case as a function of n of mystery(m, n).
✬ ✩

✫ ✪

Problem 4 (3 points)

The Fibonacci sequence is defined by the recurrence F (0) = 0, F (1) = 1 and


F ( n ) = F ( n − 1) + F ( n − 2) if n ≥ 2.


5+ 1
(a) (0.5 pts.) Let φ = 2 be the so-called golden number. Prove that φ−1 = φ − 1.
✬ ✩

✫ ✪
Mid Term Exams 43

(b) (1.5 pts.) Prove that, for any n ≥ 0, we have


φn − (−φ)−n
F (n) = √
5

✬ ✩

✫ ✪
44 Mid Term Exams

(c) (1 pt.) Prove that F (n) = Θ(φn ).


✬ ✩

✫ ✪
Mid Term Exams 45

Midterm EDA exam Length: 2.5 hours 20/04/2017

Problem 1 (2 points)

(a) (0.5 pts.) Compute the average cost of insertion sort to sort a vector with n different
log n
integers when with probability n one chooses a vector which is sorted backwards
log n
and with probability 1 − n one chooses a sorted vector.

✬ ✩

✫ ✪

(b) (0.5 pts.) Consider the following function:

bool mystery(int n) {
if (n ≤ 1) return false ;
if (n == 2) return true;
if (n%2 == 0) return false ;
for (int i = 3; i * i ≤ n; i += 2)
if (n%i == 0)
return false ;
return true;
}

✞ ☎

Complete: function ☎ computes ✝
mystery ✆and
its cost is O( ✝ ✆). Do not justify the answer.

(c) (0.5 pts.) Show that n! = O(nn ) by applying the definition (not using limits).
46 Mid Term Exams

✬ ✩

✫ ✪

(d) (0.5 pts.) Show that n! = Ω(2n ) by applying the definition (not using limits).

✬ ✩

✫ ✪

Problem 2 (3 points)

Given n ≥ 1, a sequence of n integers a0 , . . . , an−1 is unimodal if there exists t with 0 ≤ t < n


such that a0 < . . . < at−1 < at and at > at+1 > . . . > an−1 . The element at is called the
top of the sequence.

For example, the sequence 1, 3, 5, 9, 4, 1 is unimodal, and its top is 9 (take t = 3).

(a) (1.5 pts.) Implement a function int top(const vector<int>& a) in C++ which, given a
non-empty vector a that contains a unimodal sequence, returns the index of the top of
the sequence. If you use auxiliary functions that do not belong to the C++ standard
library, implement them too. The solution must have cost Θ(log n) in time in the worst
case. Justify the cost is indeed Θ(log n) and give a situation in which this worst case
takes place.
Mid Term Exams 47

✬ ✩

✫ ✪

(b) (1.5 pts.) Implement a function bool search (const vector<int>& a, int x) in C++ which,
given a non-empty vector a that contains a unimodal sequence and an integer x, returns
whether x occurs in the sequence or not. If you use auxiliary functions that do not belong
to the C++ standard library, implement them too. The solution must have cost Θ(log n)
in time in the worst case. Justify the cost is indeed Θ(log n) and give a situation in which
this worst case takes place.
48 Mid Term Exams

✬ ✩

✫ ✪

Problem 3 (2 points)

The following class vect is a simplification of the class vector of the STL:
class vect {
int sz , * data , cap ;
int new capacity ();
void reserve (int new cap);
Mid Term Exams 49

public:
vect () { sz = cap = 0; data = nullptr ; }
int& operator[](int index) { return data [index ]; }
int size () { return sz ; }
void push back(int value ) {
if (sz ≥ cap) reserve (new capacity ());
data [sz] = value ;
++sz;
} };

Used space: sz = 4
data
In an object of class vect, field sz stores the number of el-
ements that the vector currently contains. The reserved 4 2 3 1
memory for the vector, pointed by field data, always has
enough space to store the sz current elements, and possi-
bly some more. The maximum number of elements that Reserved space: cap = 6
could be stored in the reserved memory is called capacity, and is the value of field cap.
The diagram on the right illustrates a possible implementation of a vector with contents
(4, 2, 3, 1). Note shaded cells are reserved but unused.

The reason for this data structure is that calling the system to ask for more memory is an ex-
pensive operation that one does not want to perform often. Function void reserve (int new cap),
whose implementation is not detailed here, takes care of that: it asks for a new memory frag-
ment that is big enough to store new cap elements, copies the contents of the old vector there
and updates conveniently the fields sz, data and cap.

Observe that every time function push back is called, if there is not enough reserved space,
function int new capacity () is called which, using the current capacity, determines the new
capacity for function reserve .

(a) (0.5 pts.) Consider the following implementation of function new capacity:

int new capacity () {


const int A; // A is a prefixed parameter such that A ≥ 1
return cap + A; }

What is the exact value of cap in a vector that initially has cap = 0 and to which operation
reserve has been applied m times? Let us denote this value by C (m).

If we make n calls of push back over a vector which is initially empty (sz = cap = 0), how
many times exactly have we called reserve (in other words, which is the value of m such
that n ≤ C (m) and C (m − 1) < n)? Give also an asymptotic expression of this number
that is as precise and simple as possible.
50 Mid Term Exams

✬ ✩

✫ ✪

(b) (0.75 pts.) Show that the solution to the recurrence defined by C (0) = 0,
m
C (m + 1) = AC (m) + B, where A > 1 and B ≥ 1, is C (m) = BAA−−1 B for m ≥ 0.
✬ ✩

✫ ✪

(c) (0.75 pts.) The same as in exercise (a), but with the following function new capacity:

int new capacity () {


const int A, B; // A, B are prefixed parameters such that A > 1, B ≥ 1
return A*cap + B; }
✬ ✩

✫ ✪
Mid Term Exams 51

Problem 4 (3 points)

We want to have a function


int stable partition (int x, vector<int>& a)
which, given an integer x and a vector of n different integers a = ( a0 , a1 , . . . , an−1 ), reorders
the contents of the vector so that all elements of the subvector a[0..k] are less than or equal
to x, and all elements of the subvector a[k + 1..n − 1] are greater than x, and also returns the
index k (k = −1 if all elements of a are greater than x).
Moreover, the original relative order of the elements of a is respected:
• if a[i ] and a[ j] with i < j are both less than or equal to x, then in the final vector a[i ]
will occur before a[ j], and both will be placed in the “part” a[0..k] that contains the
elements ≤ x;
• if a[i ] and a[ j] with i < j are both greater than x, then in the final vector a[i ] will oc-
cur before a[ j], and both will be placed in the “part” a[k + 1..n − 1] that contains the
elements > x.
For example, given x = 2 and the sequence a = (1, 5, 3, 0, 4), we would like that the function
updated a to (1, 0, 5, 3, 4), and that it returned k = 1.
(a) (1 pt.) Implement the function stable partition in C++. The cost in time must be Θ(n).
Justify the cost. What is the cost in space of the auxiliary memory that your implemen-
tation is using?
✬ ✩

✫ ✪
(b) (0.5 pts.) What does the next function mystery do? Do not justify the answer.
52 Mid Term Exams

void mystery aux(vector<int>& a, int l, int r) {


// Pre: 0 ≤ l ≤ r < a.size()
for (int i = l , j = r ; i < j ; ++i, −−j) swap(a[i], a[ j ]);
}
void mystery(vector<int>& a, int l, int p, int r) {
// Pre: 0 ≤ l ≤ p ≤ r < a.size()
mystery aux(a, l , p );
mystery aux(a, p+1, r );
mystery aux(a, l , r );
}
✗ ✔

✖ ✕
(c) (1.5 pts.) Fill the gaps in the following alternative implementation of stable partition
and analyze its cost in time in the worst case. Assume that, in the worst case, at each
recursive call of stable partition rec we have that q − p = Θ(r − l + 1).
int stable partition (int x, vector<int>& a) {
return stable partition rec (x, a , 0, a . size ()−1);
}
int stable partition rec (int x, vector<int>& a, int l , int r) {
if ( l == r) {
✞ ☎
if (a[ l ] ≤ x) return l ;
else return ✝ ✆;
}
int m = ( l+r)/2;
int p = stable partition rec (x, a , l ✞
, m); ☎

int q = stable ☎
partition rec (x, ✞a , ✝ ☎ ✆, r);
mystery(a✞, ✝ ☎ ✆, m, ✝ ✆);
return ✝ ✆; }
Analysis of the cost:
✬ ✩

✫ ✪
Mid Term Exams 53

Midterm EDA Exam Length: 2.5 hours 06/11/2017

Problem 1 (3 points)

Answer the following questions. You do not need to justify your answers.
(a) (0.5 pts.) The cost in time of the following code snippet as a function of n:
int j = 0;
int s = 0;
for (int i = 0; i < n; ++i)
if ( i == j * j ) {
for (int k = 0; k < n; ++k) ++s;
++j;
}
✞ ☎
is Θ( ✝ ✆).

(b) (1 pt.) Given a vector of integers v and an integer x, the function


int position (const vector<int>& v, int x) {
int n = v. size ();
for (int i = 0; i < n; ++i)
if (v[ i ] == x)
return i ;
return −1;
}

examines the n = v.size() positions of v and returns the first one that contains x, or −1
if there is none.
Assume that✞x occurs☎in vector v. The asymptotic cost in time of position in the worst
case✞is Θ( ✝☎ ✆ ), and in the average case (assuming uniform probability) is
Θ( ✝ ✆).


(c) (0.5 pts.) Give the order of magnitude of☎the following function in its simplest form:
5(log n) + 2 n + cos(n ) = Θ( ✝ ✆).
2
√ 8

(d) (0.5 pts.) The solution to the recurrence


1 if 0 ≤ n < 2
T (n) = 2
4 · T (n/2) + 3n + 2 log(log n) + 1, if n ≥ 2

✞ ☎
is T (n) = Θ( ✝ ✆).
54 Mid Term Exams

(e) (0.5 pts.) The solution to the recurrence


1 if 0 ≤ n < 2
T (n) =
4 · T (n − 2) + 3n2 + 2 log(log n) + 1, if n ≥ 2
✞ ☎
is T (n) = Θ( ✝ ✆).

Problem 2 (2.5 points)

Consider the following program, which reads a strictly positive integer m and a sequence of
n integers a0 , a1 , ..., an−1 that are guaranteed to be between 1 and m:

int main() {

int m;
cin >> m;
vector<int> a;
int x;
while (cin >> x)
a. push back(x );

vector<int> b(m + 1, 0);


int n = a . size ();
for (int i = 0; i < n; ++i)
++b[ a[ i ] ];

for (int j = 1; j ≤ m; ++j)


b[ j ] += b[j −1];
}

(a) (0.5 pts.) Given y such that 0 ≤ y ≤ m, what is the value of b[y] at the end of main in
terms of the sequence a?
✬ ✩

✫ ✪

(b) (1 pt.) Let us define the median of the sequence a as the value p between 1 and m such
that b[ p] ≥ n2 and b[ p − 1] < n2 , where b is the vector computed as in the code above.

Write in C++ a function


Mid Term Exams 55

int median(int n, const vector<int>& b);

which, given n, the size of the sequence a, and b, computed as above, finds the median of
a. Solutions with cost Ω(m) will not be considered as valid answers. If you use auxiliary
functions, implement them too.
✬ ✩

✫ ✪

(c) (1 pt.) Analyze the cost of your function median of the previous exercise as a function of
m.
✬ ✩

✫ ✪
56 Mid Term Exams

Problem 3 (2 points)

Consider the type


struct complex {
int real ;
int imag;
};

for implementing complex numbers (with integer components), where real is the real part
and imag is the imaginary part of the complex number.

For example, if z is an object of type complex that represents the number 2 + 3i, then z . real =
2 and z. imag = 3.

(a) (1 pt.) Implement in C++ a function


complex exp(complex z, int n );
which, given a complex number z and an integer n ≥ 0, computes the complex num-
ber zn . The solution must have cost Θ(log n) in time. If you use auxiliary functions,
implement them too.

Note. Recall that the product of complex numbers is defined as follows:


( a + bi) · (c + di) = ( ac − bd) + ( ad + bc)i

✬ ✩

✫ ✪
Mid Term Exams 57

(b) (1 pt.) Justify that the cost in time of your function exp is Θ(log n).

✬ ✩

✫ ✪

Problem 4 (2.5 points)

Consider the following recurrence:

T (n) = T (n/2) + log n

(a) (1 pt.) Let us define the function U as U (m) = T (2m ). Using the recurrence for T, deduce
a recurrence for U.
58 Mid Term Exams

✬ ✩

✫ ✪

(b) (0.5 pts.) Solve asymptotically the recurrence for U of your answer to the previous exer-
cise.
✬ ✩

✫ ✪

(c) (1 pt.) Solve asymptotically the recurrence for T.


✬ ✩

✫ ✪
Mid Term Exams 59

Midterm EDA exam Length: 2.5 hours 19/04/2018

Problem 1 (1.5 points)

2 n
(a) (0.5 pts.) Consider the functions f (n) = nn and g(n) = 22 .
✞ ☎
Which of the two functions grows asymptotically faster? ✝ ✆

Justification:
✬ ✩

✫ ✪

2 2 n n
Note: Read nn as n(n ) , and similarly 22 as 2(2 ) .

(b) (0.5 pts.) Assume that the inputs of size n of a certain algorithm are of the following
types:

• Type 1: for each input of this type, the algorithm takes time Θ(n4 ). Moreover, the
probability that the input is of this type is n13 .

• Type 2: for each input of this type, the algorithm takes time Θ(n3 ). Moreover, the
probability that the input is of this type is n1 .

• Type 3: for each input of this type, the algorithm takes time Θ(n). Moreover, the
probability that the input is of this type is 1 − n13 − n1 .
✞ ☎
Then the cost of the algorithm in the average case is ✝ ✆.

Justification:
60 Mid Term Exams

✬ ✩

✫ ✪


(c) (0.5 pts.) Solve the recurrence T (n) = 2T (n/4) + Θ( n).

✞ ☎
Answer: T (n) = Θ( ✝ ✆).

Justification:
✬ ✩

✫ ✪
Mid Term Exams 61

Problem 2 (2 points)

In this problem we take n as a constant. Given a vector x0 ∈ Z n and a square matrix A ∈


Z n×n , we define the sequence x(0), x(1), x(2), . . . as:


x0 if k = 0
x ( k) =
A · x ( k − 1) if k > 0

For example, for n = 3, if

   
1 1 1 1
x0 =  2  and A =  1 0 0 ,
3 0 1 0
we have that
     
1 6 9
x ( 0) =  2  , x ( 1) =  1  , x ( 2) =  6  , ...
3 2 1

(a) (1 pt.) Show by induction that x(k) = Ak · x0 for all k ≥ 0.


✬ ✩

✫ ✪
62 Mid Term Exams

(b) (1 pt.) Explain at a high level how you would implement a function
vector<int> k th(const vector<vector<int>>& A, const vector<int>& x0, int k);
for computing the k-th term x(k) of the sequence defined by the matrix A and the vector
x0. Analyse also the cost in time as a function of k. The cost must be better than Θ(k).

✬ ✩

✫ ✪
Mid Term Exams 63

Problem 3 (3.5 points)

Given a natural number x, let us consider its representation in base 3. Assume that the
number of digits n in this representation is a power of 3. We split the sequence of digits in
three parts of the same size x2 , x1 and x0 , corresponding to the highest, middle and lowest
digits of x.

For example, if x = 102111212 3 , then x2 = 1023 , x1 = 1113 and x0 = 2123 .

(a) (0.5 pts.) Express x in terms of x2 , x1 and x0 . No justification is needed.


✞ ☎
x= ✝ ✆

(b) (1 pt.) Let y be another natural number with n digits in its representation in base 3, and
let us define y2 , y1 and y0 analogously. Express x · y in terms of x2 , x1 , x0 , y2 , y1 and y0 .
No justification is needed.

✞ ☎
✝ ✆· 3
✞ ☎
x·y = 4n/3

+ ✝ ✆· 3
✞ ☎
3n/3

+ ✝ ✆· 3
✞ ☎
2n/3

+ ✝ ✆· 3
✞ ☎
n/3

+ ✝ ✆

(c) (1 pt.) Express x · y in terms of x2 , x1 , x0 , y2 , y1 and y0 in such a way that strictly less
than 9 products are introduced. No justification is needed.

✞ ☎
✝ ✆· 3
✞ ☎
x·y = 4n/3

+ ✝ ✆· 3
✞ ☎
3n/3

+ ✝ ✆· 3
✞ ☎
2n/3

+ ✝ ✆· 3
✞ ☎
n/3

+ ✝ ✆

Hint: Consider ( x0 + x1 + x2 ) · (y0 + y1 + y2 ).

(d) (1 pt.) Describe at a high level an algorithm for computing the product of two given
natural numbers represented in base 3 with a number of digits that is a power of 3.
Analyse the asymptotic cost in time.
64 Mid Term Exams

✬ ✩

✫ ✪

Problem 4 (3 points)

(a) (1 pt.) Consider a recurrence of the form


T (n) = T (n/b) + Θ(logk n)
Mid Term Exams 65

where b > 1 and k ≥ 0. Show that its solution is T (n) = Θ(logk+1 n).

Justification:
✬ ✩

✫ ✪

Note: logk n is short for (log(n))k .

Hint: do a change of variable.

(b) (1 pt.) Given an n ≥ 1, a sequence of n integers a0 , . . . , an−1 is unimodal if there exists


t with 0 ≤ t < n such that a0 < . . . < at−1 < at and at > at+1 > . . . > an−1 . The
element at is called the top of the sequence. For example, the sequence 1, 3, 5, 9, 4, 1 is
unimodal, and its top is 9 (take t = 3).

Fill the gaps in the following code so that the function


bool search (const vector<int>& a, int x),
given a non-empty vector a that contains a unimodal sequence and an integer x, returns
whether x appears in the sequence or not. No justification is needed.

✞ ☎
bool search (const vector<int>& a, int x, int l , int r) {
if ( ✝ ✆) return x == a[l];
int m = ( l+r)/2;
auto beg = a .✞begin (); ☎
if (a[m] < ✝ ✆) ✞ ☎
return search (a , x, m+1, r) or binary search (beg + l , beg + ✝ ✆, x);
✞ ☎
else
return search (a , x, l , m) or binary search (beg + ✝ ✆, beg + r + 1, x);
}
66 Mid Term Exams

✞ ☎
bool search (const vector<int>& a, int x) { return search (a , x, 0, ✝ ✆); }

Note: Given an element x and iterators first, last such that the interval [first, last) is
sorted (increasingly or decreasingly), the function binary search(first, last, x) returns true
if x appears in the interval [first, last) and false otherwise, in logarithmic time in the size
of the interval in the worst case.

(c) (1 pt.) Analyse the cost in time in the worst case of a call search (a , x), where a is a vector
of size n > 0 that contains a unimodal sequence and x is an integer. Describe a situation
in which this worst case can take place.
✬ ✩

✫ ✪
Mid Term Exams 67

Midterm EDA exam Length: 2.5 hours 05/11/2018

Problem 1 (2 points)

For each of the following statements, mark with an X the corresponding cell depending on
whether it is true or false.

Note: Each right answer will add 0.2 points; each wrong answer will subtract 0.2 points,
except in the case that there are more wrong answers than right ones, in which the grade of
the exercise will be 0.

(1) (2) (3) (4) (5) (6) (7) (8) (9) (10)
TRUE
FALSE

(1) The cost in time of quicksort in the worst case is Θ(n2 ).


(2) The cost in time of quicksort in the average case is Θ(n2 ).
(3) Any algorithm that computes the sum x + y of two naturals x, y of n bits each, must have
cost in time Ω(n).
(4) There exists an algorithm that computes the sum x + y of two naturals x, y of n bits each,
in time O(n).
(5) Any algorithm that computes the product x · y of two naturals x, y of n bits each, must
have cost in time Ω(n2 ).
(6) There exists an algorithm that computes the product x · y of two naturals x, y of n bits
each, in time O(n2 ).
(7) Any algorithm that, given an integer k ≥ 0 and a matrix A of n × n integer numbers,
computes the matrix Ak must do Ω(k) products of matrices.
(8) 22n ∈ O(2n ).
(9) 2n ∈ O(n).
(10) log(2n) ∈ O(log n).

Problem 2 (3 points)

Given two matrices of Booleans A and B of size n × n, we define their logical product P = A · B
as the n × n matrix which at the coefficient of the i-th row and j-th column (0 ≤ i, j < n)
contains:
−1
n_
pij = ( aik ∧ bkj )
k=0

(a) (0.5 pts.) Consider the following function for computing the logical product:
68 Mid Term Exams

vector<vector<bool>> product1(const vector<vector<bool>>& A,


const vector<vector<bool>>& B) {
int n = A. size ();
vector<vector<bool>> P(n, vector<bool>(n, false));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k)
P[i ][ j ] = P[i ][ j ] or (A[i ][ k] and B[k][ j ]);
return P;
}

✞ ☎
What is the cost in time in the worst case in terms of n? The cost is Θ( ✝ ✆).

Give an example of worst case.


✛ ✘

✚ ✙

(b) (1 pt.) Consider the following alternative for computing the logical product:

vector<vector<bool>> product2(const vector<vector<bool>>& A,


const vector<vector<bool>>& B) {
int n = A. size ();
vector<vector<bool>> P(n, vector<bool>(n, false));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n and not P[i ][ j ]; ++k)
if (A[i ][ k] and B[k][j ]) P[i ][ j ] = true;
return P;
}
✞ ☎
What is the cost in time in the best case in terms of n? The cost is Θ( ✝ ✆).

Give an example of best case.


✛ ✘

✚ ✙

✞ ☎
What is the cost in time in the worst case in terms of n? The cost is Θ( ✝ ✆).

Give an example of worst case.


Mid Term Exams 69

✛ ✘

✚ ✙

(c) (1.5 pt.) Explain at a high level how to implement a function for computing the logical
product of matrices that is more efficient asymptotically in the worst case than those
proposed at sections (a) and (b). What is its cost in time in the worst case?
✬ ✩

✫ ✪

Problem 3 (2 points)

Consider the following function:


int mystery rec (int n, int l , int r) {
if (r == l+1) return l ;
int m = (l+r)/2;
if (m*m ≤ n) return mystery rec(n, m, r );
else return mystery rec (n, l , m);
}
70 Mid Term Exams

int mystery(int n) {
return mystery rec (n, 0, n+1);
}
(a) (1 pt.) Given an integer n ≥ 0, what does function mystery compute?
✬ ✩

✫ ✪

✞ ☎
(b) (1 pt.) What is the cost in time of mystery(n) in terms of n? The cost is Θ( ✝ ✆)

Justify your answer.


✬ ✩

✫ ✪

Problem 4 (3 points)

Consider the problem of, given a vector of integers (possibly with repetitions), sorting it in
increasing order. The following costs are in time and are asked in terms of n, the size of the
vector.
(a) (0.25✞pts.) What is the
☎ cost of the insertion sort algorithm in the best case? The cost is
Θ( ✝ ✆).
Mid Term Exams 71

(b) (0.25✞pts.) What is the☎cost of the insertion sort algorithm in the worst case? The cost is
Θ( ✝ ✆).

(c) (0.25✞pts.) What is the


☎ cost of the mergesort algorithm in the best case? The cost is
Θ( ✝ ✆).

(d) (0.25✞pts.) What is the


☎ cost of the mergesort algorithm in the worst case? The cost is
Θ( ✝ ✆).

(e) (0.75 pts.) Fill the gaps of the function my sort defined below, so that given a vector of
integers v, it sorts it increasingly:

void my sort(vector<int>& v) {
int n = v. size ();
double lim = n * log (n );
int c = 0;
for (int i = 1; i < n; ++i) {
int x = v[ i ];
✞ ☎
int j ;
; j > 0 and ✝ ☎
for ( j = i ✞ ✆; −−j) {
v[ j ] = ✝ ✆;
++c;
✞ ☎
}
v[ j ] = ✝ ✆;
if (c > lim) {
merge sort (v );
return;
}
}
}

The auxiliary function merge sort is an implementation of the mergesort algorithm, and
function log computes the neperian logarithm (that is, in base e).
✞ ☎
(f) (1.25 pts.) What is the cost of my sort in the best case? The cost is Θ( ✝ ✆).

✞ ☎
What is the cost of my sort in the worst case? The cost is Θ( ✝ ✆).

Justify your answers and give one example of best case and one of worst case.
72 Mid Term Exams

✬ ✩

✫ ✪
2
Lab Exams
74 Lab Exams

Lab Exam EDA Length: 2 hours 13/12/2010

Shift 1

Problem 1
Jutge.org, Problem P39846: Treasures in a map (4)
(https://www.jutge.org/problems/P39846_en).

Problem 2
Jutge.org, Problem P71701: Peaceful kings
(https://www.jutge.org/problems/P71701_en).

Shift 2

Problem 1
Jutge.org, Problem P84415: Bag of words
(https://www.jutge.org/problems/P84415_en).

Problem 2
Jutge.org, Problem P22295: The travelling tortoise
(https://www.jutge.org/problems/P22295_en).

Lab Exam EDA Length: 2 hours 19/5/2011

Problem 1
Jutge.org, Problem P69865: Picking up coins
(https://www.jutge.org/problems/P69865_en).

Problem 2
Jutge.org, Problem P98123: Filling the bag
(https://www.jutge.org/problems/P98123_en).

Lab Exam EDA Length: 2 hours 13/12/2011

Problem 1
Jutge.org, Problem P90766: Treasures in a map (3)
(https://www.jutge.org/problems/P90766_en).
Lab Exams 75

Problem 2
Jutge.org, Problem P67329: DNA
(https://www.jutge.org/problems/P67329_en).

Lab Exam EDA Length: 2 hours 14/05/2012

Problem 1
Jutge.org, Problem P47386: Gossip
(https://www.jutge.org/problems/P47386_en).

Problem 2
Jutge.org, Problem P87462: Pacman
(https://www.jutge.org/problems/P87462_en).

Lab Exam EDA Length: 2hours 29/11/2012

Problem 1
Jutge.org, Problem P90861: Queues of a supermarket (1)
(https://www.jutge.org/problems/P90861_en).

Problem 2
Jutge.org, Problem P14952: Topological sort
(https://www.jutge.org/problems/P14952_en).

Lab Exam EDA Length: 2 hours 22/5/2013

Problem 1
Jutge.org, Problem X07174: Nombres sense prefixos prohibits
(https://www.jutge.org/problems/X07174_ca).

Problem 2
Jutge.org, Problema X34032: El cavall afamat
(https://www.jutge.org/problems/X34032_en).
76 Lab Exams

Lab Exam EDA Length: 2 hours 4/12/2013

Problem 1
Jutge.org, Problem P60796: Treasures in a map (2)
(https://www.jutge.org/problems/P60796_en).

Problem 2
Jutge.org, Problem X21319: Circuit Value Problem
(https://www.jutge.org/problems/X21319_en).

Lab Exam EDA Length: 2 hours 19/5/2014

Problem 1
Jutge.org, Problem P81453: Shortest path
(https://www.jutge.org/problems/P81453_en).

Problem 2
Jutge.org, Problem P89318: Forbidden words
(https://www.jutge.org/problems/P89318_en).

Lab Exam EDA Length: 2 hours 22/12/2014

Problem 1
Jutge.org, Problem X41530: Forest
(https://www.jutge.org/problems/X41530_en).

Problem 2
Jutge.org, Problem X92609: Two coins of each kind (3)
(https://www.jutge.org/problems/X92609_en).

Lab Exam EDA Length: 2.5 hours 25/05/2015

Problem 1
Jutge.org, Problem P86108: LOL
(https://www.jutge.org/problems/P86108_ca).
Lab Exams 77

Problem 2
Jutge.org, Problem P27258: Monstres en un mapa
(https://www.jutge.org/problems/P27258_ca).

Lab Exam EDA Length: 2.5 hours 22/12/2015

Problem 1
Jutge.org, Problem P43164: Treasures in a map (5)
(https://www.jutge.org/problems/P43164_en).

Problem 2
Jutge.org, Problem P31389: Rooks inside a rectangle
(https://www.jutge.org/problems/P31389_en).

Lab Exam EDA Length: 2.5 hours 19/05/2016

Problem 1
Jutge.org, Problem P12887: Minimum spanning trees
(https://www.jutge.org/problems/P12887_en).

Problem 2
Jutge.org, Problem P54070: Rightmost position of insertion
(https://www.jutge.org/problems/P54070_en).

Lab Exam EDA Length: 2.5 hours 15/12/2016

Shift 1

Problem 1
Jutge.org, Problem P76807: Sudoku
(https://www.jutge.org/problems/P76807_en).

Problem 2
Jutge.org, Problem P99753: Bi-increasing vector
(https://www.jutge.org/problems/P99753_en).
78 Lab Exams

Shift 2

Problem 1
Jutge.org, Problem P18679: Balance beam (1)
(https://www.jutge.org/problems/P18679_en).

Problem 2
Jutge.org, Problem P74219: Fibonacci numbers (2)
(https://www.jutge.org/problems/P74219_en).

Lab Exam EDA Length: 2.5 hours 25/05/2017

Problem 1
Jutge.org, Problem P49889: Consonants and vowels (1)
(https://www.jutge.org/problems/P49889_en).

Problem 2
Jutge.org, Problem P96413: Erdos number (2)
(https://www.jutge.org/problems/P96413_en).

Lab Exam EDA Length: 2.5 hours 11/12/2017

Problem 1
Jutge.org, Problem P70756: Partitions
(https://www.jutge.org/problems/P70756_en).

Problem 2
Jutge.org, Problem P71496: Cuts
(https://www.jutge.org/problems/P71496_en).

Lab Exam EDA Length: 2.5 hours 28/05/2018

Problem 1
Jutge.org, Problem P29033: Two colors
(https://www.jutge.org/problems/P29033_en).

Problem 2
Jutge.org, Problem X39049: Powers of permutations
(https://www.jutge.org/problems/X39049_en).
Lab Exams 79

Lab Exam EDA Length: 2.5 hours 03/12/2018

Problem 1
Jutge.org, Problem X82938: Search in a unimodal vector
(https://www.jutge.org/problems/X82938_en).

Problem 2
Jutge.org, Problem X19647: Cheapest Routes
(https://www.jutge.org/problems/X19647_en).
3
Final Exams
82 Final Exams

Final exam EDA Length: 3 hours 20/6/2014

Problem 1: Four quickies (from the midterm) (2 points)

✞ ☎
1. Let f (n) = n log(cos(nπ ) + 4)). Then f (n) = Θ( ✝ ✆).
✞ ☎
2. Which is the last digit of 71024 written in decimal notation? Answer: ✝ ✆.


3. What is the recurrence for the cost of Strassen’s☎algorithm to multiply n × n matrices?
Answer T (n) = ✝ ✆.
4. An algorithm admits all 2n vectors of n bits as possible inputs. On 2n − 1 of these in-
puts the cost of the algorithm is Θ(n2 ), and on the remaining one the cost is Θ(n4 ).
Therefore, its worst-case cost is Θ(n4 ) and its best-case cost is Θ(n2 ). What is its
average-case cost when the input is chosen uniformly at random (so each input has
probability 1/2n )? ✞ ☎
Answer: T (n) = Θ( ✝ ✆).

✬ for questions 1, 2 and 4 (reasoning for question 3 is not required):


Reasoning ✩

✫ ✪

Problem 2: Binary search trees and AVLs (3 points)

For this problem, use the following representation of BSTs:


struct node {
Elem x; // Information of the node
node* lc ; // Pointer to left child
node* rc ; // Pointer to right child
Final Exams 83

node(Elem x, node* lc , node* rc ) : x( x ), lc ( lc ), rc ( rc ) {}


˜node() { delete lc ; delete rc ; }
};
typedef node* bst ; // A BST is a pointer to the root (null if empty)

(a) (1.0 points) Implement a C++ function bst redo (const vector<Elem> &v) that recon-
structs a binary search tree from its preorder traversal v. For example, on input v = [2 1 7 3 8],
the function should produce the following tree:
2

1 7

3 8

You may assume that v is the correct preorder of some BST. If you need so, you may imple-
ment an auxiliary function.
✬ ✩

✫ ✪
84 Final Exams

(b) (1.0 points) Implement a C++ function bst build AVL(const vector<Elem> &v) that re-
constructs a BST that satisfies the AVL property from a sorted vector of elements v. If you
need so, you may implement an auxiliary function.
✬ ✩

✫ ✪

(c) (1.0 points) If we add a field n. height to denote the height of node n in the BST where
it sits (with leaves at height 0 and therefore NULLs would be at height −1), complete the
following code so that the result indicates if the BST T is an AVL:

bool is AVL(bst T) {
if (T == NULL) return true;
else if (T−>lc == NULL or T−>rc == NULL) return (T−>height ≤ 1);
✬ ✩
else {

✫ ✪
} }
Final Exams 85

Problem 3: Hamiltonian paths in tournament graphs (3 points)

Let us represent directed graphs with adjacency matrices:


typedef vector<vector<bool>> Graph;

A tournament graph is a directed graph in which there is exactly one arc between every pair
of different vertices, and that does not have any arc from any vertex to itself.

a) (0.5 points) Write a C++ function that tells whether a given graph with n vertices is a
tournament graph in Θ(n2 ) time in the worst case.
bool is tournament(const Graph& G) {
✬ ✩

✫ ✪
}

b) (1.0 points) Prove, by induction on the number of vertices, that every tournament graph
has a Hamiltonian path, that is, a path that visits every vertex exactly once (hint: show that
a new vertex can be inserted in a path of n − 1 vertices to get a path of n vertices).
✬ ✩

✫ ✪

c) (1.0 points) Using the previous proof, give an algorithm that returns a Hamiltonian path
of a tournament graph (clarity will be more valued than efficiency):
86 Final Exams

// Pre: G is a tournament graph


// Post: the result is a list of vertices that forms a Hamiltonian path in G
list <int> path(const Graph &G) {
✬ ✩

✫ ✪
}

d) (0.5 points) Analize the cost of your solution.


✬ ✩

✫ ✪
Final Exams 87

Problem 4: Reductions (1 point)

The problem of Hamiltonian cycles in directed graphs is:

DHAM: Given a directed graph, determine whether there is a cycle that visits all
vertices exactly once.

The problem of Hamiltonian cycles in undirected graphs UHAM is the same, but where the
input graph is undirected. Steffy knowns that DHAM can be reduced to UHAM by simply
applying the following transformation to each of the vertices v of the directed graph:

IN MID OUT
v v v v

Roy and Johnny say that vertex vMID is not actually needed: they say connecting vIN — vOUT
and ignoring vMID is enough. But Steffy replies: “Guys, take a look at this input to DHAM
and then we talk again”:
e c
a

d b

What did Steffy mean? Is she right? (be concise but precise, please)
✬ ✩

✫ ✪
88 Final Exams

Problem 5: Bellman-Ford (competència transversal) (1 point)

Recall (from the practical work of the competència transversal) that Bellman-Ford algorithm
allows one to find minimum-weight paths in a weighted directed graph, even when weights
are negative.

✞ cost of Bellman-Ford
(a) (0.5 points) Which is the worst-case ☎ algorithm on a graph with |V |
vertices and | E| edges? Answer: Θ( ✝ ✆)

(b) (0.5 points) Steffy says that the statement at the beginning of this exercise cannot be
completely right, since otherwise one could efficiently find a Hamiltonian cycle in a directed
graph G = (V, E) by simply assigning weight −1 to each edge in G, choosing any vertex
s, and applying Bellman-Ford to check if the minimum-weight path from s to one of the
vertices that have an edge towards s has weight −(|V | − 1). How can you explain this
paradox? (or have we proved that P = NP?)
✬ ✩

✫ ✪
Final Exams 89

Final exam EDA Length: 3 hours 16/1/2015

Problem 1: Asymptotic analysis (the same as in the midterm!) (2 points)

(1 point) Prove that ∑ni=0 i3 = Θ(n4 ).

Hint: There are several ways to do it, and one of them is to consider the O and the Ω
separately.
✬ ✩

✫ ✪

Note: Second part in the back.


log n
(1 point) Let f (n) = 2 and g(n) = n. Which one is asymptotically faster? Prove it.
90 Final Exams

✬ ✩

✫ ✪

Problem 2: Binary search trees and AVLs (3 points)

With the usual representation of binary search trees (this also holds for AVLs), some algo-
rithms may be inefficient. For instance, function smaller (T, x) that given a tree T and a key
x, returns the number of elements in T that have a key ≤ x.

The following modification in the representation


struct node {
node* lft ;
node* rgt ;
Key k; // generic type
Value v; // generic type
int size ; // size of the subtree rooted at this node ***** NEW *****
};
Final Exams 91

typedef node* bst ;

allows, between others, an implementation of smaller (T, x) with cost Θ(h), where h is the
height of T (which would be Θ(log n) on average for a random BST and Θ(log n) in the
worst case for an AVL, where n is the size of T).

(1,5 points) Write in C++ an efficient implementation of the function

✬ ✩
int smaller ( bst T, const Key& x)

✫ ✪

Note: Next question in the back.


(1,5 points) Write in C++ the modification of the insert (T,k, v) procedure that inserts a new
pair hk, vi in a tree T. This procedure has as a precondition that k is not in T. Your implemen-
tation of insert () must have the same cost it would have under the usual representation of
BSTs but, of course, somehow it must update the size attribute. Note that you are not asked
to maintain the AVL property, nor that T is an AVL.

// Precondition: T does not contain k


void insert ( bst& T, const Key& k, const Value& v)
92 Final Exams

✬ ✩

✫ ✪

Problem 3: Graphs and NP-completeness (3 points)

A mate of your is preparing the EDA lab exam and gets stuck in a problem in the “Graph
Algorithms” list of the Judge. After a bit of thought, she realizes that this problem essen-
tially asks to determine whether an undirected graph represented with adjacency lists is
2-colorable. That is, is it is possible to assign a red or blue color to each vertex so that no two
adjacent vertices are painted with the same color?

Unfortunately, the Judge responds Time Limit Exceeded to all her submissions! At this mo-
ment, your mate decides to look for some more efficient code in the Internet and finds the
following implementation in a web forum:
bool two col aux(const vector<vector<int>>& g, int u, vector<bool>& col,
vector<bool>& marked, bool is red) {
col [u] = is red ;
marked[u] = true;
for (int i = 0; i < g[u]. size (); ++i) {
Final Exams 93

int v = g[u][ i ];
if (not marked[v]) {
if (not two col aux (g, v, col , marked, not is red )) return false ;
}
}
return true;
}

bool two colourable (const vector<vector<int>>& g) {


int n = g. size ();
vector<bool> marked(n, false);
vector<bool> col(n);
for (int u = 0; u < n; ++u) {
if (not marked[u]) {
if (not two col aux (g, u, col , marked, false )) return false ;
}
}
return true;
}

Now, she expects that the code will be efficient enough, since after a bit of analysis, she
knows it takes O(|V | + | E|) time. After sending it to the Judge, the verdict is... Wrong Answer!

(2 points) Write a correct version of two col aux so that two colorable () properly determines
if a graph is 2-colorable within O(|V | + | E|) time.

bool two col aux(const vector<vector<int>>& g, int u, vector<bool>& col,


vector<bool>& marked, bool is red)
94 Final Exams

✬ ✩

✫ ✪

(1 point) Thanks to your help (hopefully!), your mate could fix the code and get it accepted.
Irritated, she continues reading the forum. The author of the code affirms there that his
program can be easily extended to solve the 3-colorability problem with the same asymptotic
complexity. Do you believe him? Why or why not?
✬ ✩

✫ ✪

Problem 4: Algorithmic culture (2 point)

Given a directed graph whose arcs have costs that can be negative, we wish to determine if
it contains one or more negative cost cycles (just if they exist, not how many there are, nor
Final Exams 95

which are they).

(0,5 points) Give the proper name of a famous algorithm that helps solving this problem
with just a little adaptation.

✎ ☞

✍ ✌

(0,5 points) Briefly explain (but with enough details to implement it) how this algorithm
works.

✬ ✩

✫ ✪

(0,5 points) What is the cost of this algorithm? Express it using the number of vertices |V |
and the number of arcs | E| in the input graph.

✎ ☞

✍ ✌

(0,5 point) Explain how to adapt the general algorithm to our particular problem (negative
96 Final Exams

cycle detection).
✬ ✩

✫ ✪
Final Exams 97

Final exam EDA Length: 3 hours 12/6/2015

One from the midterm, one from that thing, and one more (2 points)

✞ ☎
(1 point) Determine if they are equal (=) or different (6=), and prove it:

Θ(3log2 (n) ) ✝ ✆Θ(3log4 (n) ).


✬ ✩

✫ ✪

(0.5 points) What is the algorithm from the competencia transversal useful for? Choose only
one (reasoning not requested):
• To compute the most likely philogenetic tree.
• To compute the optimal price of a long option over a finantial product.
• To fit all 9 Beethoven symphonies into a single CD.
• To solve recurrences that do not match the form of the master theorems.

(0.5 points) The S UBSET S UM problem is the following: Given a list of natural numbers
a1 , . . . , am and a target b, all written in decimal notation, determine if there exists a subset
S ⊆ {1, . . . , m} such that ∑i∈S ai = b. If d is the number of digits of the largest natural number
in the input, indicate which is the only correct assertion (reasoning not requested):
• The problem is NP-complete and, therefore, there does not exist any algorithm of cost
O(m · d · 10d ) unless P = NP.
• The problem is NP-complete and, therefore, there does not exist any algorithm of cost
polynomial in m and d unless P = NP.
98 Final Exams

• The problem is NP-complete but nonetheless a known algorithm exists whose cost is
polynomial in both m and d.

• The problem can be solved in time O(d · m · log m), and hence cost polynomial in the
size of the input, as follows: first, all m numbers are added to a max-heap; then, the
numbers are extracted one by one until either the sum exceeds b, or all numbers are
extracted without reaching b, or the sum of the extracted numbers is exactly b.

Pointers (2 points)

Given two binary trees, create a new binary tree that is their intersection (and leave the given
trees untouched). For example:

1
0
0
1 1
0
0
1 1
0
0
1
1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1
0
1
0
1 0
1
0 1
1 0
0
1 0
1
0 1
1 0
0
1 0
1
0
1

1
0
0
1 1
0
0
1 1
0
0
1
1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1
0
1
0 1
1 0
0
1 0
1
0
1 0
1
0
1 0
1
0
1
1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1 1
0
0
1

(1.5 points) Using the type and header as given, solve this problem.

struct Node { // nodes do not store data; just pointers to children


Node* left ; // pointer to left child
Node* right ; // pointer to right child
};

typedef Node* Tree;

Tree intersection ( Tree t1 , Tree t2) {


Final Exams 99

✬ ✩

✫ ✪
}

(0.5 points) What is its cost, in the worst case, as a function of the sizes n1 and n2 of t1 and
t2?
✬ ✩

✫ ✪

Backtracking fill-in-the-gaps (2 points)

Onions is a logical puzzle1 in which we are given a square matrix n × n divided into n
regions, each region painted with a different color.

1 The original puzzle is called Alberi (tree in Italian) and the apps (both iOS and Android) for this game were

tremendously successful a few years ago.


100 Final Exams

The goal of the puzzle is to plant n onions in such a way that


• each row contains exactly one onion,
• each column contains exactly one onion,
• each region contains exactly one onion,
• there are no two horizontally, vertically, or diagonally adjacent onions; in other words,
all cells surrounding an onion must be free.
Using the following definition
struct Cell {
int color ; // the color (between 0 and n-1) of its region
bool has onion ; // indicates if there is an onion in it or not
}

typedef vector<vector<Cell> > OnionBoard;

fill in the gaps in the C++ code below for the corresponding backtracking algorithm to find
one solution, or determining that no solution exists. If there is more than one solution, any
solution is good.
class Onions {
int n;
bool solution found ;
OnionBoard board; // current partial solution
vector<int> col; // col[i] = column of the onion at row i
vector<bool> onion in col; // onion in col[i] = there is an onion in column i
vector<bool> onion in region; // onion in region[i] = there is an onion in region i

public:
Onions(const OnionBoard& initial board) {
board = initial board ;
n = board . size ();
col = vector<int>(n);
onion in col = vector<bool>(n, false);
onion in region = vector<bool>(n, false);
solution found = false ;
backtrack (0);
Final Exams 101

void backtrack (int k) {


if (k == n) { solution found = true; return; }
for (int j = 0; j <✞ n and not solution found ; ++j) { ☎
int cell col = ✝ ✆
if (not onion in col [ j ] and not onion in region [ cell col ]
and not onion in neighborhood (k, j )) {
✬ ✩
col [k] = j ;

✫ ✪

backtrack (k+1); ✩

✫ ✪
}} }

// returns true iff the partial solution board has an onion in a cell adjacent to (i,j);
// you are not asked to implement it
bool onion in neighborhood (int i , int j );

Tweets (4 points)

A social network of the Twitter type has different users. These maintain a ‘follow’ relation-
ship with other users (for instance, Salvador follows Anna, Ivet and Leo Messi, but Leo
Messi does not follow anyone). Users can add or remove other users from their list of fol-
lowed users. Moreover, at any moment, a user can tweet a message. Also, at any time, a
user can obtain the k most recent tweets of the users she follows. (That is, if she follows n
users, she gets at most k tweets, not nk).

The dimensions of such a system are what one would imagine:


• The number of users is huge; the number of tweets is even bigger.
• The number of users followed by some users may be big, but not huge.
• Some users are followed by many other users.
• The number of tweets per user has a high variability.
• The value of k is relatively small; something between 10 and 1000, say.

Users are represented by a User struct that contains its personal data (including a string with
its name that identifies it in a unique way) and that tweets are represented with a struct
Tweet that contains the message and its posting time:
struct User {
... // personal data
string name; // different users have different names
102 Final Exams

};

struct Tweet {
string message; // body of the message
int post time ; // number of miliseconds since some epoch
};

Explain which data structures and algorithms you would use to store the described in-
formation and to implement the following operations in the most efficient way: adding
and removing follow relationships, tweeting a message, and obtaining the k most recent
tweets from the users that are followed by a given user. Do not explain how users are creat-
ed/deleted. Analyse the cost of your operations.

The expected answer is open but be specific defining the SocialNetwork data structure and
describe (without code) how to implement the following operations:

struct SocialNetwork { ... };

// u1 follows u2 (if she didn’t already); users exist.


void add follower (SocialNetwork& sn, string u1, string u2);

// u1 unfollows u2 (if she did); users exist.


void remove follower (SocialNetwork& sn, string u1, string u2);

// u tweets the message m; user exists.


void tweet message (SocialNetwork& sn, string u, Tweet m);

// Returns a list with the k most recent tweets of the users followed by u; user exists.
list <Tweet> k most recent tweets (const SocialNetwork& sn, string u, int k );
Final Exams 103

✬ ✩

✫ ✪
104 Final Exams

Final EDA Exam Length: 3 hours 07/01/2016

Problem 1 (3 pts.)

Answer the following questions:


(a) (1 pt.) Consider the following decision problems:

• SAT: given a propositional formula, to determine whether it is satisfiable.

• COL: given a graph G = (V, E) and a natural number k, to determine whether G


can be painted with k colors so that the extremes of edges are painted with different
colors.

• SOR: given an array of n different integers, to determine whether it is sorted in


increasing order.
For each of the statements that follow, mark with an ’X’ the corresponding column,
depending on whether the statement is true, false, or is an open problem and it is still
unknown if it is true or false. No justification is needed.

Cert Fals Obert


SOR is in class P
SOR is in class NP
SOR is NP-hard
SAT is in class P
SAT is in class NP
SAT is NP-hard
SOR can be reduced polynomially to COL
COL can be reduced polynomially to SOR
SAT cannot be reduced polynomially to SOR
COL can be reduced polynomially to SOR, and
SAT cannot be reduced polynomially to SOR

(b) (1 pt.) Given a vector of integers v and an integer x, the function


int position (const vector<int>& v, int x) {
int n = v. size ();
for (int i = 0; i < n; ++i)
if (v[ i ] == x) return i ;
return −1;
}
returns the first position of v that contains x, or −1 if there is none.
Final Exams 105

Consider a probability distribution over the input parameters such that the probability
that x is element v[i ] is n1 for 0 ≤ i < n.
✞ ☎
Answer: the average-case cost in time of position as a function of n is Θ( ✝ ✆).
Justification:
✬ ✩

✫ ✪

(c) (1 pt.) What does Floyd-Warshall’s algorithm compute? What is its cost in time and
space in the worst case? (no justification is needed)
✬ ✩

✫ ✪

Problem 2 (2 pts.)

Let V be a vector<int> with n different integers. Consider this code snippet:

set <int> S;
for (int i = 0; i < n; ++i) {
S. insert (V[i ]);
106 Final Exams

cout << *S.begin () << ' ' ;


}

(a) (0.4 pts.) What does the code snippet write if n = 6 and the elements of V are 42 100 23
12 20 24 (in this order)?

✤ ✜

✣ ✢

(b) (0.4 pts.) Give a high-level explanation on which values are written by the code snippet
with an arbitrary V with n different integers.

✬ ✩

✫ ✪

(c) (0.4 pts.) Justify what is the asymptotic cost in time of the code snippet in the worst case
as a function of n.

Hint: You can use Stirling’s formula: log(n!) = Θ(n log n).

✬ ✩

✫ ✪

(d) (0.4 pts.) If the elements of V were repeated, could the code snippet compute something
different from what was answered in exercise (b)? If the answer is yes, show an example.
If the answer is no, explain why.
Final Exams 107

✬ ✩

✫ ✪

(e) (0.4 pts.) Write with full detail an alternative program to the given code snippet that
computes the same for an arbitrary vector V with n different integers (n ≥ 1), but with
asymptotic cost in time strictly less than that computed in exercise (c). Justify what is
this asymptotic cost.
✬ ✩

✫ ✪

Problem 3 (2 pts.)

Consider the problem of, given a directed acyclic graph G = (V, E), generating all its topo-
logical orderings. The next program solves it (assume V = {0, 1, ..., n − 1}):
108 Final Exams

#include <iostream>
#include <vector>
using namespace std;

typedef vector<int> AdjList;


typedef vector<AdjList> Graph;

// implementation not given here


Graph read graph ();
void print solution (const vector<int>& sol);

bool ok(const Graph& G, const vector<int>& sol) {


int n = sol . size ();
vector<bool> mar(n, false);
for (int i = 0; i < n; ++i) {
int x = sol [ i ];
if (mar[x]) return false ;
mar[x] = true;
for (int y : G[x])
for (int j = 0; j < i ; ++j)
if ( sol [ j ] == y) return false ;
}
return true;
}

void top sorts rec (int k , const Graph& G, vector<int>& sol) {


int n = sol . size ();
if (k == n) {
if (ok(G, sol ))
print solution ( sol );
}
else
for (int x = 0; x < n; ++x) {
sol [k] = x;
top sorts rec (k+1, G, sol );
}
}

void top sorts (const Graph& G, vector<int>& sol) {


top sorts rec (0, G, sol );
}
int main() {
Graph G = read graph ();
vector<int> sol(G.size ());
top sorts (G, sol );
}

However, it is too slow. Rewrite function top sorts to solve the problem more efficiently,
without changing main. Implement also the auxiliary functions that you use, except for
print solution and the functions of the standard C++ library.
Final Exams 109

✬ ✩

✫ ✪

Problem 4 (3 pts.)

Let G be the adjacency matrix of a directed graph with n vertices. The closure matrix of (the
graph represented by) G, which we will represent with G ∗ , is an n × n matrix defined as
follows: given u, v such that 0 ≤ u, v < n, the coefficient in row u and column v is


∗ 1 if there is a (possibly empty) path from u to v in the graph
Guv =
0 otherwise
110 Final Exams

where the vertices of the graph are identified with the integers from 0 to n − 1 as usual.

(a) (1 pt.) Give a high-level description of how to implement a function

vector<vector<int>> closure(const vector<vector<int>>& G);

which, given the adjacency matrix G of a directed graph, returns its closure. Analyze
the asymptotic cost in time in the worst case.

✬ ✩

✫ ✪

(b) (1 pt.) Let us denote by I the n × n identity matrix, that is, the matrix where all coeffi-
cients are 0 except for those in the diagonal, which are 1. Show that, for any k ≥ 0, there
is a path in the graph from u to v with at most k edges if and only if the coefficient in
row u column v of the matrix ( I + G )k (the matrix resulting from multiplying k matrices
I + G) is different from 0, i.e., ( I + G )kuv 6= 0.
Final Exams 111

✬ ✩

✫ ✪

(c) (1 pt.) Give a high-level description of an algorithm for, given the adjacency matrix of a
directed graph G, computing its closure G ∗ in time strictly better than Θ(n3 ) in the worst
case. Give the cost in the worst case and justify it. Assume that the cost of arithmetic
operations with integers is constant.
Hint: if there is a path from u to v, there is at least one with at most n − 1 edges.
✬ ✩

✫ ✪
112 Final Exams

Final EDA Exam Length: 3 hours 07/01/2016

Problem 1 (1.5 pts.)

Answer the following questions:

(a) (0.9 pt.) The master theorem for dividing recurrences claims that if we have a recurrence
of the form T (n) = aT (n/b) + Θ(nk ) with a > 0, b > 1 and k ≥ 0, then, letting α = logb a,

 ✞ ☎

 ✞ ✆

if α < k,


T (n) = ✝
✞ ✆

if α = k,

✝ ✆ if α > k.


(b) (0.3 pt.) The smallest k such that the following statement is true:

“For all directed graph G = (V, E), it holds that | E| = O(|V |k )”


✞ ☎
is ✝ ✆.

(c) (0.3 pt.) Class stack <T> of STL has two member functions top:

T& top ();


const T& top() const;

On the other hand, class priority queue <T> has one function top only:

const T& top() const;

What is the problem with class priority queue <T> having a function T& top()?
✬ ✩

✫ ✪
Final Exams 113

Problem 2 (1.5 pts.)

In this exercise, shaded nodes represent red nodes.

Wrong answers penalize with the same grade as right ones reward.
✞ ☎
(a) The following binary tree is a red-black tree (answer Yes or No): ✝ ✆

3 9

NULL NULL NULL NULL

✞ ☎
(b) The following binary tree is a red-black tree (answer Yes or No): ✝ ✆

3 9

1 6 NULL NULL

NULL NULL NULL NULL

✞ ☎
(c) The following binary tree is a red-black tree (answer Yes or No): ✝ ✆

1 7

NULL NULL
5 9

3 6 NULL NULL

NULL NULL NULL NULL

✞ ☎
(d) The following binary tree is a red-black tree (answer Yes or No): ✝ ✆
114 Final Exams

3 8

NULL NULL
2 4

NULL NULL NULL NULL

✞ ☎
(e) The following binary tree is a red-black tree (answer Yes or No): ✝ ✆

2 8

NULL
1 5 9

3 6 NULL NULL
NULL NULL

NULL NULL NULL NULL

✞ ☎
(f) The following binary tree is a red-black tree (answer Yes or No): ✝ ✆

3 8

2 4 NULL NULL

NULL NULL NULL NULL

Problem 3 (2 pts.)

Let s ∈ R be such that 0 < s < 1.

Consider the following variant of binary search which, given:


• an element x,
Final Exams 115

• a vector v that is sorted in non-decreasing order, and

• two positions l and r,

returns a position between l and r, both included, in which x appears in v (or −1 if there is
none):

double s; // 0 < s < 1

int position (double x, const vector<double>& v, int l, int r) {


if ( l > r) return −1;
int p = l + int(s *( r −l ));
if (x < v[p]) return position (x, v, l , p−1);
if (x > v[p]) return position (x, v, p+1, r );
return p;
}

(a) (0.75 pt.) According to the value of the parameter s, give a recurrence that describes the
cost in time in the worst case of position as a function of n = r −l+1.
✬ ✩

✫ ✪

(b) (0.5 pt.) According to the value of s, when does that worst case take place?
✬ ✩

✫ ✪

(c) (0.75 pt.) According to the value of s, solve the recurrence of the answer of exercise (a)
and give the asymptotic cost in the worst case.
116 Final Exams

✬ ✩

✫ ✪

Problem 4 (2 pts.)

A deque<T> (acronym of double-ended queue, pronounced: “dèk”) is a sequential container


of objects of type T that allows inserting and deleting elements both at the beginning as well
as at the end, by means of the following functions:

void push front (const T& x); void push back (const T& x);
void pop front (); void pop back ();

respectively. Also, one can recover the element at the beginning with the functions:

T& front ();


const T& front () const;

All these functions have cost in time Θ(1).


Final Exams 117

(a) (1 pt.) A weighted directed graph G = (V, E) is binary if for any edge e ∈ E, its weight is
0 or 1. By using a deque, implement in C++ a function

int minimum cost(const vector<vector<pair<int,int>>>& G, int x, int y);

that, given a binary graph G and two vertices x and y of G, returns the minimum cost of
going from x to y (or −1 if it is not possible to go from x to y).

Assume vertices are represented with integers between 0 and n − 1, where n is the num-
ber of vertices; and that the graph is represented with adjacency lists with a vector<vector<pair<int,int>>
where the first component of the pair s represents the successor vertex and the second
one, the weight of the edge.

✬ ✩

✫ ✪

(b) (0.5 pt.) Analyze the cost in time of your function minimum cost in the worst case as a
function of the number of vertices |V | and edges | E|.
118 Final Exams

✬ ✩

✫ ✪

(c) (0.5 pt.) Which cost in time in the worst case would minimum cost have if we used the
version of Dijkstra’s algorithm that implements the priority queue with a binary heap
(like the ones seen at class)?
✬ ✩

✫ ✪

Problem 5 (3 pts.)

The problem of DISEQUALITIES consists in, given an interval of integers and a set of dise-
qualities (6=) between variables, to determine whether there is a solution to all disequalities
with values in the interval. More formally, given:
• a (finite) interval [l, u] ⊂ Z,
• a set of variables V, and
• a set D of disequalities of the form x 6= y, where x, y ∈ V,
we have to determine where there is s : V → Z such that:
• for any x ∈ V we have s( x) ∈ [l, u], and
• for any x 6= y ∈ D it holds s( x) 6= s(y).
Final Exams 119

We will consider that the set of variables is of the form V = { x0 , x1 , . . . , xn−1 } for a cer-
tain n > 0, and will identify the variables with integers between 0 and n − 1. Besides,
we will represent the inputs for the problem of DISEQUALITIES by means of the type
inp DISEQUALITIES defined as follows:
struct inp DISEQUALITIES {
int l , u, n;
set <pair<int,int>> D; // each pair (i, j) is a disequality xi 6= x j
};
(a) (1 pt.) Complete the following implementation of the function
bool has solution (const inp DISEQUALITIES& e);
that solves the problem of DISEQUALITIES:

bool ok(const vector<int>& s, const set<pair<int,int>>& D) {


✞ ☎
for (auto d : D)
if ( ✝ ✆)
return false ;
return true;
}

bool has solution (int k , vector<int>& s, const inp DISEQUALITIES& e) {


✞ ☎ ✞ ☎
if (k == e.n) return ok(s , e .D);
for (int v = ✝ ✆; v ≤
✞ ☎ ✝ ✆; ++v) {
✝ ✆
if ( has solution (k+1, s , e )) return true;
}
return false ;
}
bool has solution (const inp DISEQUALITIES& e) {
✞ ☎
vector<int> s(e.n);
return has solution ( ✝ ✆, s, e);
}
(b) (0.75 pt.) Prove that the cost in time in the worst case of the previous implementation of
has solution is Ω((u − l + 1)n ).
✬ ✩

✫ ✪
(c) (0.75 pt.) Consider the problem of COLORING: given an undirected graph G and a
natural number c > 0, to determine whether one can paint the vertices of G with c colors
in such a way that any edge has the endpoints painted with different colors.
120 Final Exams

Suppose that we represent the inputs for the problem of COLORING with the type
inp COLORING defined as follows:
struct inp COLORING {
vector<vector<int>> G; // graph represented with adjacency lists
int c ;
};
Implement a polynomial reduction from COLORING to DISEQUALITIES:
inp DISEQUALITIES reduction(const inp COLORING& ec);
✬ ✩

✫ ✪
(d) (0.5 pt.) Do you see feasible to find a polynomial algorithm for DISEQUALITIES? Why?
✤ ✜

✣ ✢
Final Exams 121

Final EDA Exam Length: 3 hours 12/01/2017

Problem 1 (2 pts.)

Fill the following gaps as precisely as possible:

✞ ☎
(a) (0.25 pts.) A graph with n vertices has O( ✝ ✆) edges.
✞ ☎
(b) (0.25 pts.) A connected graph with n vertices has Ω( ✝ ✆) edges.
✞ ☎
(c) (0.25 pts.) A complete graph with n vertices has Ω( ✝ ✆) edges.
✞ ☎
(d) (0.25 pts.) A min-heap with n vertices has Θ( ✝ ✆) leaves.
✞ ☎
(e) (0.25 pts.) A binary search tree with n vertices has height Ω( ✝ ✆).
✞ ☎
(f) (0.25 pts.) A binary search tree with n vertices has height O( ✝ ✆).
✞ ☎
(g) (0.25 pts.) An AVL tree with n vertices has height Ω( ✝ ✆).
✞ ☎
(h) (0.25 pts.) An AVL tree with n vertices has height O( ✝ ✆).

Problem 2 (3 pts.)

Let G = (V, E) be a directed graph with weights ω : E → R. We want to solve the problem
of, given a vertex s ∈ V, to compute the distance from s to all vertices of the graph.

Recall that:
• a path is a sequence of vertices that are connected consecutively by arcs; that is to say,
(u0 , u1 , . . . , uk ) such that for all 1 ≤ i ≤ k, we have (ui−1 , ui ) ∈ E.
• the weight of a path is the sum of the weights of its arcs:

k
ω ( u0 , u1 , . . . , u k ) = ∑ ω ( u i−1 , u i ) .
i=1

• the distance of a vertex u to a vertex v is the weight of the path (called minimum path)
with minimum weight among those leaving from u and arriving at v, if it exists.
(a) (0.2 pts.) Let us assume that for any edge e ∈ E, we have ω (e) = 1; that is to say, all
weights are 1. Which algorithm can we use to solve efficiently the problem of the dis-
tances?
☛ ✟

✡ ✠
122 Final Exams

(b) (0.2 pts.) Let us assume that for any edge e ∈ E, we have ω (e) ≥ 0; that is to say, all
weights are non-negative. Which algorithm can we use to solve efficiently the problem
of the distances?
☛ ✟

✡ ✠

(c) (0.2 pts.) Which algorithm can we use to solve efficiently the problem of the distances,
if some weights can be negative?
☛ ✟

✡ ✠

(d) (0.4 pts.) Which condition over the cycles of the graph must be satisfied so that, for all
pairs of vertices u, v ∈ V, there exists a minimum path from u to v?
✬ ✩

✫ ✪

(e) (1 pt.) A function π : V → R is a potential of the graph if it satisfies that, for any edge
(u, v) ∈ E, we have π (u) − π (v) ≤ ω (u, v). Moreover, the reduced weights ωπ are defined
as ωπ (u, v) = ω (u, v) − π (u) + π (v) for any (u, v) ∈ E.
Prove that if c is a path from u to v then ωπ (c) = ω (c) − π (u) + π (v).
✬ ✩

✫ ✪
Final Exams 123

(f) (1 pt.) Suppose that the graph has a potential π. Then, it can be proved that for all pairs
of vertices u, v ∈ V there is a minimum path with weights ω from u to v. Assuming this
fact, explain how to use the potential π to compute the distance from a given vertex
s to all vertices of the graph with an alternative algorithm to that of part (c) when the
weights can be negative.
✬ ✩

✫ ✪

Problem 3 (2 pts.)

We define a type matrix to represent square matrices of real numbers. Consider the following
program:
typedef vector<vector<double>> matrix;

matrix aux(const matrix& A, const matrix& B) {


int n = A. size ();
matrix C(n, vector<double>(n, 0));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k)
C[i ][ j ] += A[i][k] * B[k][ j ];
return C;
}

matrix mystery(const matrix& M) {


int n = M.size ();
matrix P(M), Q(M);
for (int i = 1; i < n; ++i) {
P = aux(P, M);
Q = aux(Q, P);
}
return Q;
}
124 Final Exams

(a) (0.5 pts.) What does the function matrix mystery(const matrix& M) compute in terms of
the matrix M?

✤ ✜

✣ ✢

(b) (0.5 pts.) If M is an n × n matrix, what is the cost in the worst case of the function
matrix mystery(const matrix& M) as a function of n? Justify your answer.

✬ ✩

✫ ✪

(c) (1 pt.) Implement in C++ a function that computes the same as the function matrix mystery(const matrix&
and which takes Θ(n3 log n) time in the worst case. Also implement the auxiliary func-
tions you use, except for aux and the functions of the standard library of C++. Justify
that the cost of your function is as required.
Final Exams 125

✬ ✩

✫ ✪

Problem 4 (3 pts.)

The problem of HAMILTONIAN GRAPH consists in, given an (undirected) graph, to decide
whether it is Hamiltonian, that is to say, whether there exists a cycle that visits all its vertices
exactly once. It is well-known that HAMILTONIAN GRAPH is an NP-complete problem.
126 Final Exams

It is also known that, from the proof that a problem belongs to class NP, one can derive a
brute force algorithm that solves it. The following function bool ham(const vector<vector<int>>& G)
which, given a graph G represented with adjacency lists, returns if G is Hamiltonian, imple-
ments this algorithm in the case of HAMILTONIAN GRAPH.
1 bool ham rec(const vector<vector<int>>& G, int k, vector<int>& p) {
2 int n = G. size ();
3 if (k == n) {
4 vector<bool> mkd(n, false);
5 for (int u : p) {
6 if (mkd[u]) return false ;
7 mkd[u] = true;
8 }
9 for (int k = 0; k < n; ++k) {
10 int u = p[k ];
11 int v;
12 if (k < n−1) v = p[k+1];
13 else v = p [0];
14 if ( find (G[u].begin (), G[u].end (), v) == G[u].end()) return false ;
15 }
16 return true;
17 }
18 for (int v = 0; v < n; ++v) {
19 p[k] = v;
20 if (ham rec(G, k+1, p)) return true;
21 }
22 return false ;
23 }
24

25 bool ham(const vector<vector<int>>& G) {


26 int n = G. size ();
27 vector<int> p(n);
28 return ham rec(G, 0, p );
29 }

Note: The function of the STL library


Iterator find ( Iterator first , Iterator last , int val );

returns an iterator to the first element in the range [first, last) that compares equal to val. If
no such element exists, the function returns last.
(a) (0.5 pts.) Identify the variable in the previous program which represents the witness
when the function ham returns true.
✞ ☎

✝ ✆

(b) (0.5 pts.) Identify the code corresponding to the verifier in the previous program. To
that end, use the line numbers on the left margin.
✞ ☎

✝ ✆
Final Exams 127

(c) (1 pt.) Fill the following gaps so that the function ham2 computes the same as the func-
tion ham, but more efficiently.
bool ham2 rec(const vector<vector<int>>& G, int k, int u, vector<int>& next) {
int n✞= G. size

();
if ( ✝ ✆ == n) ✞ ☎
return find (G[u].begin (), G[u].end (), ✝ ✆) 6= G[u].end();

✞ ☎
for (int v : G[u])

✞ ✝ ☎ ✆
if (next[v] == ){
next[u] = ✝ ✆;
if (ham2 rec(G, k+1, v, next )) return true;
next[u] = −1;
}
return false ;
}

bool ham2(const vector<vector<int>>& G) {


int n = G. size ();
✞ ☎
vector<int> next(n, −1);
return ham2 rec(G, ✝ ✆, 0, next);
}
(d) (0.5 pts.) Suppose that the adjacency lists of the representation of G are sorted (for exam-

✤ ✜
ple, increasingly). Explain how to use this to make the function of part (c) more efficient.

✣ ✢
(e) (0.5 pts.) Suppose that G is a disconnected graph. Explain how to use this to make the

✗ ✔
function of part (c) more efficient.

✖ ✕
128 Final Exams

Final EDA Exam Length: 3 hours 09/06/2017

Problem 1 (2 pts.)

(a) (0.5 pts.) Given the following max-heap:

84

52 79

36 45 73 71

18 12 13

draw the max-heap resulting from adding 55 and deleting the maximum element (in
this order). You do not need to justify anything.
✬ ✩

✫ ✪

(b) (0.5 pts.) Using that P ⊆ NP, prove that P ⊆ co-NP.


✬ ✩

✫ ✪

(c) (0.5 pts.) Consider the following function:


int f (const vector<int>& v, int i, int j ) {
// Precondition: 0 ≤ i ≤ j < v.size()
if ( i == j) return v[ i ];
int p = ( j − i + 1)/3;
Final Exams 129

int m1 = i+p;
int m2 = m1+p;
return f (v, i , m1) + f (v, m1+1, m2) + f(v, m2+1, j );
}

Compute the asymptotic cost in time of f as a function of n = j − i + 1.

✬ ✩

✫ ✪

(d) (0.5 pts.) Consider the following statement:

The function nn grows asymptotically faster than any other function.

Is it true? If so, justify it. Otherwise give a counterexample.

✬ ✩

✫ ✪
130 Final Exams

Problem 2 (2 pts.)

Given a vector A with n different integers and another vector B with m different integers,
we want to compute a vector (of different integers) which is the intersection of the two (that
is, that contains the common elements).

For example, if A = (3, 1, 6, 0) and B = (4, 6, 1, 2, 7), then any of the two vectors (1, 6), (6, 1)
would be a valid answer.

Let us assume that A and B are not necessarily sorted. Give a high-level description of how
you would implement a function
vector<int> intersection (const vector<int>& A, const vector<int>& B);

that returns the intersection of A and B with a cost in time of O(n + m) in the average case.
Justify the cost.
✬ ✩

✫ ✪
Final Exams 131

Problem 3 (3 pts.)

Given a directed acyclic graph (DAG) G, the level of its vertices is defined inductively as
follows:
• if v is a root of G (a vertex without predecessors) then level(v) = 0
• otherwise,

level(v) = 1 + max{level(u) | u is a predecessor of v}

Moreover, the depth of G is the largest level of any vertex:

depth( G ) = max{level(v) | v vertex of G }

(a) (0.9 pts.) Fill out the following table pointing out, for each vertex of the given DAG, its
level. What is the depth of the DAG? You do not need to justify anything.

C
B D

A E
G
H
F

A B C D E F G H
level : depth :

(b) (0.4 pts.) For each of the following statements, mark with an X the corresponding cell
depending on whether it is true or false. You do not need to justify anything.
Note: Every right answer will add 0.1 points; every wrong answer will subtract 0.1
points, except when there are more wrong answers than right ones, in which case the
grade of the exercise will be 0.
(1) For any vertex u of a DAG G, if u is a leaf (vertex without successors) then level(u) =
depth( G ).
(2) For any vertex u of a DAG G, if level(u) = depth( G ) then u is a leaf.
(3) The depth of a DAG with n vertices is O(n).
(4) The depth of a DAG with n vertices is Ω(log n).
(1) (2) (3) (4)
TRUE
FALSE
(c) (1.7 pts.) Here it is assumed that graphs are represented with adjacency lists, and that
vertices are identified with consecutive natural numbers 0, 1, etc.
Fill the gaps of the following function:
vector<int> levels(const vector<vector<int>>& G);
132 Final Exams

which, given a DAG G = (V, E), returns a vector that, for each vertex u ∈ V, contains the
value level(u) in position u. Give and justify the cost in time in the worst case in terms
of n = |V | and m = | E|.

vector<int> levels(const vector<vector<int>>& G) {


int n = G. size ();
vector<int> lvl(n, −1), pred(n, 0);

for (int u = 0; u < n; ++u)


for (int v : G[u])
++pred[v];

queue<int> Q;
for (int u = 0; u < n; ++u)
if (pred[u] == 0) {
✞ ☎
Q.push(u);

✝ ✆
}

while (not Q.empty()) {


int u = Q.front (); Q.pop ();
for (int v : G[u]) {
✞ ☎
−− pred[v];

✝ ✆
if (pred[v] == 0) Q.push(v);
} }
return lvl ;
}
Cost and justification:
✬ ✩

✫ ✪

Problem 4 (3 pts.)

Given n > 0, a derangement (of size n) is a permutation of {0, . . . , n − 1} without fixed points;
that is, π is a derangement if and only if π (i ) 6= i for all i, 0 ≤ i < n. For example π = (2, 0, 3, 1)
Final Exams 133

is a derangement, but π ′ = (1, 3, 2, 0) is not (since π ′ (2) = 2).

Fill out the following C++ code for generating all derangements of size n. You do not need
to justify anything.

void write (const vector<int>& p, int n) {


for (int k = 0; k < n; ++k) cout << ” ” << p[k];
cout << endl;
}

✞ ☎
void generate (int k , int n, vector<int>& p, vector<bool>& used) {
if ( ✝ ✆) write(p, n);
else {
for (int✞ i = 0; i < n; ++i) ☎
( ✝
if ✞ ☎✆
){


✞ ✆

✝ ✆
✞ ☎
generate (k+1, n, p, used );

✝ ✆
}
}
};

void generate all (int n) {


vector<int> p(n);
✞ ☎
vector<bool> used(n, false);
generate ( ✝ ✆, n, p, used);
}
134 Final Exams

Final EDA Exam Length: 3 hours 19/01/2018

Problem 1 (2.5 pts.)

In this exercise, by heaps we mean min-heaps of integer numbers. We will also assume their
usual implementation, in which a complete binary tree with n elements is represented with
a vector of size n + 1 whose first component (the one with index 0) is not used.
(a) (1.25 pts.) Let v be a vector of size n + 1 that represents a complete binary tree with n
integers. Moreover, except possibly for a certain node with index i (where 1 ≤ i ≤ n),
it meets the min-heap property: if a node has a value x and one of its descendants has
value y, then x ≤ y.
Implement in C++ the function
void shift down (vector<int>& v, int i );
which sinks the node with index i until the min-heap property is restored for all nodes.
✬ ✩

✫ ✪

(b) (1.25 pts.) Implement in C++ a function


void update (vector<int>& v, int i, int x );
which given:
• a vector v that represents a heap with n integers,
• an index i such that 1 ≤ i ≤ n, and
• an integer x,
Final Exams 135

assigns the value x to the node with index i (discarding the previous value in the node)
and updates v so that it still represents a heap.
You can use the function shift down of the previous exercise, as well as the following
function shift up :
void shift up (vector<int>& v, int i) {
if ( i 6= 1 and v[i/2] > v[i ]) {
swap(v[i ], v[ i /2]);
shift up (v, i /2);
} }
✬ ✩

✫ ✪

Problem 2 (2 pts.)

Given a permutation π of {1, . . . , n}, the value π (i ) is a left maximum if π (i ) > π ( j) for all j,
1 ≤ j < i. The first element π (1) is always a left maximum.

For example π = (3, 1, 5, 4, 6, 2) has 3 left maxima (namely, π (1) = 3, π (3) = 5 and π (5) = 6).

Fill the gaps in the following C++ code that writes the permutations of {1, . . . , n} that have
exactly k left maxima, where 1 ≤ k ≤ n.

int n, k ;
vector<int> perm;
vector<bool> used;

void write () {
cout << perm[1];
136 Final Exams

for (int i = 2; i ≤ n; ++i) cout << ' ' << perm[i];


cout << endl;
}


void generate (int i , int lm,☎int mx) { ✞ ☎

if ( ✞ ✆ > k or ✝ ☎ ✆ < k ) return;
if ( ✝ ✆) write();
else {
✞ ☎
for (int j = 1; j ≤ n; ++j)
if ( ✝
✞ ☎✆
){

✝ ✞ ☎ ✆


perm[i] = ✝ ✆; ☎
if ( ✝ ✆) generate(i+1, lm+1, j);
✞ ☎
else generate ( i+1, lm, mx);

✝ ✆
}
}
}

int main() {
cin >> n >> k;
perm = vector<int>(n+1);
used = vector<bool>(n+1, false);
generate (1, 0, 0);
}

Problem 3 (3 pts.)

(a) (1 pt.) Consider the following program:


int x = ...; // initialized to some value
int mystery(const string& s) {
int h = 0;
for (int k = s . size () − 1; k ≥ 0; −−k)
h = x*h + int(s[k ]);
return h;
}

What is function mystery computing?


✤ ✜

✣ ✢
Final Exams 137

If one wanted to use function mystery as a hash function for the type string, would 0 be
an adequate value for x? Why?
✬ ✩

✫ ✪

(b) (1 pt.) For each of the following statements, mark with an X its cell depending on
whether it is true or false. You do not need to justify anything.
Note: Each right answer will add 0.25 points; each wrong answer will subtract 0.25
points, except for the case when there are more wrong answers than right ones, in which
the grade of the exercise will be 0.
Recall: SAT is the problem of, given a propositional formula, to decide whether it is
satisfiable or not; and HAM is the problem of, given a graph, to decide whether it is
hamiltonian.
(1) If there exists an NP problem that belongs to P then P = NP.
(2) If there is a polynomial reduction from a problem X to SAT then there is a polyno-
mial reduction from X a HAM.
(3) There are problems of the class NP for which there is no known algorithm that solves
them.
(4) If a problem X can be reduced polynomially to a problem Y ∈ P then X ∈ P.
(1) (2) (3) (4)
TRUE
FALSE

(c) (0.5 pts.) Consider the following forest of rooted trees, which represents a collection of
disjoint sets:
0 5

1 2 6 7 8

3 4 9 10

✞ ☎
11

The value returned by find(2) is ✝ ✆.


✞ ☎
The value returned by find(9) is ✝ ✆.

(d) (0.5 pts.) Consider the following variant of binary search, which given:
• an element x,
138 Final Exams

• a vector v sorted in non-decreasing order, and


• two positions l and r,
returns a position between l and r where x appears in v (or −1 if there is none):

int posicio (double x, const vector<double>& v, int l, int r) {


if ( l > r) return −1;
int p = l + int (( r −l)/3.0);
if (x < v[p]) return posicio (x, v, l , p−1);
if (x > v[p]) return posicio (x, v, p+1, r );
return p;
}

Analyze the asymptotic cost in the worst case.


✬ ✩

✫ ✪

Problem 4 (2.5 pts.)

Given two digraphs G1 = (V, E1 ) and G2 = (V, E2 ) defined over the same set of vertices V,
the composition of G1 and G2 is the digraph denoted by G1 ◦ G2 whose vertices are V, and
whose edges are the following set:

E = {(u, w) | ∃v such that(u, v) ∈ E1 ∧ (v, w) ∈ E2 }

Note: In this exercise it is allowed that digraphs have auto-cycles, that is, edges of the form
(u, u).

(a) (0.5 pts.) Consider the following digraphs G1 and G2 :

2 2
1 3 1 3
0 0
6 6
5 4 5 4

G1 G2
Final Exams 139

Draw G1 ◦ G2 .

✬ ✩

✫ ✪

(b) (1 pt.) Assume that G1 and G2 are represented with adjacency matrices. Implement in
C++ a function

typedef vector<vector<int>> matrix;


matrix comp(const matrix& G1, const matrix& G2);

which, given the adjacency matrices of G1 and of G2 , computes the adjacency matrix of
G1 ◦ G2 in time Θ(|V |3 ) in the worst case. Justify that the cost is as required.
140 Final Exams

✬ ✩

✫ ✪

(c) (1 pt.) Explain how to implement function comp in time better than Θ(|V |3 ).
✬ ✩

✫ ✪
Final Exams 141

Final EDA Exam Length: 3 hours 20/06/2018

Problem 1 (2 pts.)

(a) (0.5 pts.) Class stack <T> of STL has two member functions top:

T& top ();


const T& top() const;

On the other hand, class priority queue <T> has one function top only:

const T& top() const;

What is the problem with class priority queue <T> having a function T& top()?
✬ ✩

✫ ✪
(b) (0.5 pts.) For the alphabet { A, B, C, D } and the following table of absolute frequencies
for 100 characters, give a Huffman code and draw its tree. You do not need to justify
anything.

A 70
B 10
C 15
D 5
✬ ✩

✫ ✪
(c) (0.5 pts.) Draw the AVL tree resulting from inserting the three keys x, y, z in this order
to the AVL tree of the figure. Note that the keys are ordered in alphabetic order. You do
not need to justify anything.
142 Final Exams

f s

c j r v

a d i m q u

✬ ✩

✫ ✪

(d) (0.5 pts.) Given the following max-heap:

84

52 79

36 45 73 71

18 12 13

draw the max-heap resulting from adding 55 and deleting the maximum element (in
this order). You do not need to justify anything.
Final Exams 143

✬ ✩

✫ ✪

Problem 2 (3 points)

(a) (1 pt.) Consider a recurrence of the form

T (n) = T (n/b) + Θ(logk n)

where b > 1 and k ≥ 0. Show that its solution is T (n) = Θ(logk+1 n).

Justification:
✬ ✩

✫ ✪

Note: logk n is short for (log(n))k .

Hint: do a change of variable.

(b) (1 pt.) Given an n ≥ 1, a sequence of n integers a0 , . . . , an−1 is unimodal if there exists


t with 0 ≤ t < n such that a0 < . . . < at−1 < at and at > at+1 > . . . > an−1 . The
144 Final Exams

element at is called the top of the sequence. For example, the sequence 1, 3, 5, 9, 4, 1 is
unimodal, and its top is 9 (take t = 3).

Fill the gaps in the following code so that the function

bool search (const vector<int>& a, int x),

given a non-empty vector a that contains a unimodal sequence and an integer x, returns
whether x appears in the sequence or not. No justification is needed.

✞ ☎
bool search (const vector<int>& a, int x, int l , int r) {
if ( ✝ ✆) return x == a[l];
int m = ( l+r)/2;
auto beg = a .✞begin (); ☎
if (a[m] < ✝ ✆) ✞ ☎
return search (a , x, m+1, r) or binary search (beg + l , beg + ✝ ✆, x);
✞ ☎
else
return search (a , x, l , m) or binary search (beg + ✝ ✆, beg + r + 1, x);
}
✞ ☎
bool search (const vector<int>& a, int x) { return search (a , x, 0, ✝ ✆); }

Note: Given an element x and iterators first, last such that the interval [first, last) is
sorted (increasingly or decreasingly), the function binary search(first, last, x) returns true
if x appears in the interval [first, last) and false otherwise, in logarithmic time in the size
of the interval in the worst case.

(c) (1 pt.) Analyse the cost in time in the worst case of a call search (a , x), where a is a vector
of size n > 0 that contains a unimodal sequence and x is an integer. Describe a situation
in which this worst case can take place.
Final Exams 145

✬ ✩

✫ ✪

Problem 3 (3 pts.)

A student of EDA is preparing for the lab exam and gets stuck in a problem of the list
“Graph Algorithms” of the Judge. After thinking for a while, he realizes that he must,
essentially, given a graph (undirected, represented with adjacency lists), determine whether
it is 2-colorable; that is, whether it is possible to assign a color red or blue to each vertex of
the graph, so that adjacent vertices are not painted with the same color.

Unfortunately, the Judge returns a Time Limit Exceeded verdict to all his submissions. At
this point the student decides to look in the Internet for a more efficient code, and finds the
following one in a forum:
bool two col aux(const vector<vector<int>>& g, int u, vector<bool>& col,
vector<bool>& marked, bool is red) {
col [u] = is red ;
marked[u] = true;
for (int v : g[u]) {
if (not marked[v]) {
if (not two col aux (g, v, col , marked, not is red )) return false ;
}
}
146 Final Exams

return true;
}

bool two colourable (const vector<vector<int>>& g) {


int n = g. size ();
vector<bool> marked(n, false);
vector<bool> col(n);
for (int u = 0; u < n; ++u) {
if (not marked[u]) {
if (not two col aux (g, u, col , marked, false )) return false ;
}
}
return true;
}

Now he expects that this code will be efficient enough, since after a bit of analysis he con-
cludes that it takes time O(|V | + | E|). He submits it to the Judge, and it turns out that...
Wrong Answer!

(a) (2 pts.) Write a correct version of two col aux so that two colorable determines whether
a graph is 2-colorable in time O(|V | + | E|).

bool two col aux(const vector<vector<int>>& g, int u, vector<bool>& col,

✬ ✩
vector<bool>& marked, bool is red)

✫ ✪
Final Exams 147

(b) (1 pt.) Finally the student finds a way to fix the code and the Judge accepts it. Uneasy,
he carries on reading the forum. The author of the wrong code claims that his program
can be easily extended to the problem of 3-colorability with the same asymptotic cost.
Do you believe it? Why?
✬ ✩

✫ ✪

Problem 4 (2 pts.)

Consider the following problem: given n positive integer numbers a0 , a1 , ..., an−1 and two
other integers l and u such that 0 ≤ l ≤ u ≤ ∑in=−01 ai , we have to find all possibles solutions
( x0 , x1 , . . . , xn−1 ) ∈ {0, 1}n to the double inequation:

l ≤ a0 x0 + a1 x1 + · · · + a n − 1 x n − 1 ≤ u
(a) (1 pt.) Complete the following program to solve the previous problem:
int n, l , u;
vector<int> a;
vector<bool> x;

void sols (int k , int sum chosen, int sum rest) {


if (k == n) {
for (int i = 0; i < n; ++i) cout << x[i ];
cout << endl;
} else {✞ ☎
if ( ✝ ✆) {
x[k] = 0; sols (k+1, sum chosen, sum rest − a[k ]);
✞ ☎
}
if ( ✝ ✆) {
x[k] = 1; sols (k+1, sum chosen + a[k ], sum rest − a[k ]);
} }}

int main() {
cin >> n >> l >> u;
a = vector<int>(n);
for (int i = 0; i < n; ++i) cin >> a[i ];

int s = 0;
for (int i = 0; i < n; ++i) s += a[i ];

x = vector<bool>(n);
148 Final Exams

✞ ☎ ✞ ☎ ✞ ☎
sols ( ✝ ✆, ✝ ✆, ✝ ✆);
}

(b) (1 pt.) The program in the previous exercise writes the solutions in increasing lexico-
graphic ordering. For example, for the input n = 3, l = 3, u = 5 and ai = i + 1 (0 ≤ i ≤ 2),
the output is:
001
011
101
110
Explain how to change function sols to write all solutions in decreasing lexicographic
ordering, that is, in the reverse order of the previous example, without using additional
space. In particular, the algorithm consisting in storing all the output in a vector, and at

✬ ✩
the end sort it and write it will not be considered as a valid answer.

✫ ✪
Final Exams 149

Final EDA Exam Length: 3 hours 14/01/2019

Problem 1 (3.5 pts.)


(a) (0.75 pts.) Draw the AVL tree resulting from adding 31 to the AVL tree below:

50

25 70

12 35 65 86

10 30 40

✬ ✩

✫ ✪
(b) (0.75 pts.) Draw the heap resulting from removing the maximum from the following
max-heap:

84

52 29

36 45 23 21

18 12 13
✬ ✩

✫ ✪
✞ ☎
(c) (0.5 pts.) The solution to the recurrence T (n) = 3T (n/9) + Θ(n) is ✝ ✆
150 Final Exams

✞ ☎
(d) (0.5 pts.) The solution to the recurrence T (n) = 3T (n/9) + Θ( n) is ✝ ✆

✞ ☎
(e) (0.5 pts.) The solution to the recurrence T (n) = 3T (n/9) + Θ(1) is ✝ ✆

(f) (0.5 pts.) Consider the following flow network with origin s and destination t, and the
indicated flow:
3; 4
v1 v3
4; 4 3; 3
1; 3 0; 2
s t

0; 6 1; 1
v2 v4
1; 3

For each arc, we indicate the flow along the arc and its capacity, separated by a semi
colon. E.g., the arc from v1 to v3 carries 3 units of flow and has capacity 4.
Draw the residual network of this network with respect to the given flow.
✬ ✩

✫ ✪

Problem 2 (4 pts.)

In this exercise we will work with a type polynomial for representing polynomials in a vari-
able x with integer coefficients.
Final Exams 151

(a) (0.5 pts.) Suppose that we implement polynomials with vectors of integers (that is,
polynomial is vector<int>), so that for k = 0, 1, . . . the k-th value of the vector is the coef-
ficient of xk . Hence, for example the vector {1, 0, −3} represents the polynomial 1 − 3x2 .
Given a polynomial p and integers c 6= 0 and k ≥ 0, consider the following function:

polynomial mystery(const polynomial& p, int c , int k) {


int n = p. size ();
polynomial q(n + k, 0);
for (int i = 0; i < n; ++i)
q[ i + k] = c *p[ i ];
return q;
}

Answer: ✞ ☎
the function mystery computes ✝ ✞ ☎ ✆
and its cost in time in terms of n = p. size () and k is Θ ✝ ✆.

(b) (1.5 pts.) Suppose that now we implement polynomials with a dictionary with integer
keys and integer values, so that a pair of the dictionary with key k and value v (with
v 6= 0) represents the monomial v · xk . So for example the dictionary with pairs key-
value {(0, 1), (2, −3)} represents the polynomial 1 − 3x2 .
More specifically, let us assume that polynomial is unordered map<int,int>.

Which of the data structures seen at class could be ☎


✞ used for implementing unordered map<int,int>?
✝ ✆

Fill the gaps in the following reimplementation of the function mystery that uses this
new representation of polynomials.

polynomial mystery(const polynomial& p, int c , int k) {


polynomial q;
✞ ☎ ✞ ☎
for (auto mon : p)
q[ ✝ ✆] = ✝ ✆;
return q;
}

Give and justify an accurate upper bound of the cost in time in the average case.
✬ ✩

✫ ✪
152 Final Exams

(c) (0.25 pts.) From this section onwards we will suppose again that we implement polyno-
mials with vectors of integers (that is, polynomial is vector<int>).

Consider the following function, which defines the operator + for polynomials for writ-
ing in C++ the sum of two polynomials p and q as p + q:

polynomial operator+(const polynomial& p, const polynomial& q) {


polynomial s(max(p. size (), q. size ()));
for (int i = 0; i < p. size (); ++i)
s[ i ] += p[i ];
for (int i = 0; i < q. size (); ++i)
s[ i ] += q[i ];
return s ;
}

Let n = max( p.size(), q.size()).

Answer: ✞ ☎
the cost of the function in terms of n is Θ( ✝ ✆).

(d) (1.75 pts.) Fill the gaps in the following function, which defines the operator ∗ for poly-
nomials for writing in C++ the product of two polynomials p and q as p ∗ q. You can use
the functions that appear in the previous sections. Suppose that p.size() = q.size() = n,
where n ≥ 1 is a power of 2. The cost of the function must be strictly better than Θ(n2 ).

polynomial operator*(const polynomial& p, const polynomial& q) {


✞ ☎
int n = p. size ();
if (n == 1) return ✝ ✆;
int n2 = n/2;

polynomial p0(n2), p1(n2);


for (int k = 0; k < n2; ++k) p0[k] = p[k ];
for (int k = n2; k < n; ++k) p1[k − n2] = p[k ];

polynomial q0(n2), q1(n2);


for (int k = 0; k < n2; ++k) q0[k] = q[k ];
for (int k = n2; k < n; ++k) q1[k − n2] = q[k ];

polynomial p0 q0 = p0 * q0;
polynomial p1 q1 = p1 * q1;
Final Exams 153

✬ ✩

✫ ✪
}

Analyse the cost of the function in terms of n.


✬ ✩

✫ ✪

Problem 3 (2.5 pts.)

Given a natural N ≥ 1, we consider the set of the first N naturals {0, . . . , N − 1}. A set cover
of {0, . . . , N − 1} is a collection of subsets S0 , ..., S M−1 of {0, . . . , N − 1} such that each of the
S −1
first N naturals is included in at least one of the subsets, that is, iM =0 Si = {0, . . . , N − 1}.

The problem of SET-COVER consists in, given:


• two naturals K and N,
• subsets S0 , ..., S M−1 of {0, . . . , N − 1} that cover {0, . . . , N − 1},
to determine if, among the given subsets, one can choose k subsets Si0 , Si1 , ..., Sik −1 with k ≤ K
which also form a set cover of {0, . . . , N − 1}.

For example, suppose that N = 4, S1 = {0, 1, 3}, S2 = {0, 3} and S3 = {0, 2, 3}. Then if K = 2
the answer is TRUE (since S1 ∪ S3 = {0, 1, 2, 3}), but if K = 1 the answer is FALSE (since there
is no single Si that covers the set {0, 1, 2, 3}).
154 Final Exams

(a) (0.75 pts.) Consider the following implementation of the function

bool set cover (int K, int N, const vector<set<int>>& S);

for solving the problem of SET-COVER:

bool set cover rec (int K, int N, const vector<set<int>>& S,


vector<int>& w, int c) {
if (c == N) return true;
if (K == 0) return false ;
for (int i = 0; i < S. size (); ++i) {
for (int x : S[i ]) {
if (w[x] == 0) ++c;
++w[x];
}
if ( set cover rec (K−1, N, S, w, c )) return true;
for (int x : S[i ]) {
−−w[x];
if (w[x] == 0) −−c;
} }
return false ;
}

bool set cover (int K, int N, const vector<set<int>>& S) {


vector<int> w(N, 0);
return set cover rec (K, N, S, w, 0);
}

This implementation has a serious efficiency bug. Explain what is this error and rewrite
the previous code with the required changes to fix it.
Final Exams 155

✬ ✩

✫ ✪

(b) (1 pt.) Given a graph G = (V, E), a vertex cover is a subset of vertices W ⊆ V such that
every edge {u, v} ∈ E has at least one of the two endpoints in W, that is, u ∈ W or v ∈ W.

The problem of VERTEX-COVER consists in, given a natural K and a graph G = (V, E),
156 Final Exams

to determine whether there exists a subset W ⊆ V with at most K vertices that is a vertex
cover of G.

Of the two functions defined next, one is a reduction of VERTEX-COVER to SET-COVER


and the other is not. Prove that the right one is indeed correct and give a counterexample
for the wrong one.

(1) Given G = (V, E), with V = {u0 , . . . , u N −1 },

f (K, G ) = (K, N, S),

where S = {Se | e ∈ E} and Se = {i | ui ∈ e}.

(2) Given G = (V, E), with E = {e0 , . . . , e N −1 },

g(K, G ) = (K, N, S),

where S = {Su | u ∈ V } and Su = {i | u ∈ ei }.

Correct reduction and proof:


✬ ✩

✫ ✪
Incorrect reduction and counterexample:
Final Exams 157

✬ ✩

✫ ✪

(c) (0.75 pts.) Suppose we have been able to reduce VERTEX-COVER to SET-COVER, and
that we know that VERTEX-COVER is NP-complete. Can we deduce only from this
that SET-COVER is an NP-complete problem? If so, justify it. Otherwise show that
SET-COVER is NP-complete (assuming that VERTEX-COVER reduces to SET-COVER
and that VERTEX-COVER is NP-complete).
✬ ✩

✫ ✪
4
Solutions to Mid Term Exams
160 Solutions to Mid Term Exams

Solution Midterm Exam EDA 31/03/2016

Proposed solution to problem 1

(a) Θ(nlog 7 )
(b) The master theorem for subtractive recurrences states that given a recurrence T (n) =
aT (n − c) + Θ(nk ) with a, c > 0 and k ≥ 0 then

k
 Θ( n )
 if a < 1,
T ( n ) = Θ( n k+1 ) if a = 1,
 n
Θ( a c ) if a > 1.

(c) Θ(n)

Proposed solution to problem 2

(a) The cost of the program is determined by the sum of the costs of two groups of instruc-
tions:
A. The instructions that are executed at each iteration of the loop: the evaluation of
the condition i ≤n, the call f ( i ), the evaluation of the condition i == p and the
increment i++.
B. The instructions that are executed when the condition of the if is true: the call g(n)
and the increment p *= 2.
We count separately the contribution to the total cost of the two groups of instructions:
A. If the cost of f (m) is Θ(m), then at the i-th iteration the cost of A is Θ(i ). So in total
the contribution to the cost is ∑ni=1 Θ(i ) = Θ(∑ ni=1 i ) = Θ(n2 ).
B. If the cost of g(m) is Θ(m), then every time that the condition of the if is true the
cost of B is Θ(n). Since this happens Θ(log n) times, the contribution to the total
cost is Θ(n log n).
Hence in total the cost of h(n) is Θ(n2 ) + Θ(n log n) = Θ(n2 ).

(b) Let us consider the same two groups of instructions of the previous exercise, and again
we count separately their contribution to the total cost:
A. If the cost of f (m) is Θ(1), then the cost of A at each iteration is Θ(1). Since Θ(n)
are performed, the cost in total is Θ(n).
B. If the cost of g(m) is Θ(m2 ), then every time that the condition of the if is true the
cost of B is Θ(n2 ). Since this happens Θ(log n) times, the cost is Θ(n2 log n).
Hence in total the cost of h(n) is Θ(n) + Θ(n2 log n) = Θ(n2 log n).
Solutions to Mid Term Exams 161

Proposed solution to problem 3

(a) The i-th row uses i + 1 cells (0 ≤ i < n). In total, the consumed space is

n −1 n
∑ ( i + 1) = ∑ j = Θ ( n 2 ) .
i=0 j=1

(b) A possible solution:

int p(int x) { return x *(x+1)/2;}

int mystery(int k , int l , int r) {


if ( l+1 == r) return l ;
int m = ( l+r)/2;
if (p(m) ≤ k) return mystery(k , m, r );
else return mystery(k , l , m);
}

pair <int,int> row column(int n, int k) {


if (k < 0 or k ≥ p(n)) return {−1,−1};
int i = mystery(k, 0, n );
return {i , k − p(i )};
}

(c) Let C ( N ) be the cost in the worst case of a call to the function mystery(k, l , r), where
N = r − l + 1. The recurrence that describes C ( N ) is

C ( N ) = C ( N/2) + Θ(1),

since one makes one recursive call over an interval of half the size, and operations that
take constant time. By using the master theorem of divisive recurrences, the solution to
the recurrence is C ( N ) = Θ(log N ).

Therefore, the cost in the worst case of a call to function row column(n, k) is Θ(log n).

(d) The index i of the searched row is the natural number 0 ≤ i < n such that p(i ) ≤ k <
p(i + 1). We can compute it by solving the second degree equation p( x) = k and taking
i = ⌊ x ⌋:

int p(int x) { return x *(x+1)/2;}

pair <int,int> row column(int n, int k) {


if (k < 0 or k ≥ p(n)) return {−1,−1};
int i ( floor (( sqrt (1.+8* k) − 1)/2));
return {i , k − p(i )};
}
162 Solutions to Mid Term Exams

Proposed solution to problem 4

(a) Let us show it by contradiction. Let us assume that i is such that 0 ≤ i < n − 1 i f A (i +
1) < f A (i ). Let us take k = i + 1, j = f A (i + 1) and l = f A (i ), so that 0 ≤ i < k < n and
0 ≤ j < l < n. Since j = f A (k), we have that Ak,j ≤ Ak,l . And as l = f A (i ), we have
that Ai,l ≤ Ai,j ; in fact, since j < l, it must be Ai,l < Ai,j . Thus, by adding we have that
Ai,l + Ak,j < Ai,j + Ak,l . This contradicts that A is a Monge matrix.

(b) For each even i, one can compute the column where the leftmost minimum of the i-th
row of A appears as follows. From the recursive call over B1 , we have the column j1
where the leftmost minimum of the i-th row of A appears between columns 0 and n2 − 1.
Similarly, from the recursive call over B2 , we have the column j2 where the leftmost
minimum of the i-th row of A appears between columns n2 and n − 1. Hence, f A (i ) = j1
if Ai,j1 ≤ Ai,j2 , and f A (i ) = j2 otherwise.
For each odd i, one determines f A (i ) by examining the columns between f A (i − 1) and
f A (i + 1) (defining f A (n) = n − 1 for notational convenience), and choosing the index
where the leftmost minimum appears. This has cost Θ( f A (i + 1) − f A (i − 1) + 1). In
total:
n −1
n
∑ Θ( f A (i + 1) − f A (i − 1) + 1) = Θ((n − 1) − f A (0) +
2
) = Θ( n )
i=1,i odd

since 0 ≤ f A (0) < n.

(c) Let C (n) be the cost of the proposed algorithm for computing the function f A for all
rows of a Monge matrix A of size n × n.
Apart from the two recursive calls in step (2) over matrices of size n2 × n2 , steps (1) and
(3) require time Θ(n) in total. So the recurrence that describes the cost is

C (n) = 2C (n/2) + Θ(n).

By using the master theorem of divisive recurrences, the solution to the recurrence is
C (n) = Θ(n log n).
Solutions to Mid Term Exams 163

Solution Midterm Exam EDA 07/11/2016

Proposed solution to problem 1

Best case Average case Worst case


Quicksort Θ(n log n) Θ(n log n) Θ( n2 )
(a) (with Hoare’s partition)
Mergesort Θ(n log n) Θ(n log n) Θ(n log n)
Insertion Θ( n ) Do not fill Θ( n2 )

(b) Θ( n)

(c) Θ( n log n)
(d) Θ(n)
(e) Karatsuba’s algorithm computes the product of two natural numbers of n bits in time
Θ(nlog2 3 ).
(f) Strassen’s algorithm computes the product of two matrices of size n × n in time Θ(nlog2 7 ).

Proposed solution to problem 2

(a) A possible solution:


#include <vector>

using namespace std;

bool dic search (const vector<int>& a, int l , int r , int x) {


if ( l > r) return false ;
int m = ( l+r)/2;
if (a[m] < x) return dic search (a , m+1, r, x );
if (a[m] > x) return dic search (a , l , m−1, x);
return true;
}

bool search (const vector<int>& a, int l , int r , int x) {


if ( l+1 == r) return a[ l ] == x or a[r] == x;
int m = ( l+r)/2;
if (a[m] ≥ a[l ]) {
if (a[ l ] ≤ x and x ≤ a[m]) return dic search (a , l , m, x );
else return search (a , m, r , x );
}
else {
if (a[m] ≤ x and x ≤ a[r]) return dic search (a , m, r , x );
else return search (a , l , m, x );
} }

bool search (const vector<int>& a, int x) {


164 Solutions to Mid Term Exams

return search (a , 0, a . size ()−1, x );


}
(b) Let C (n) be the cost of dealing with a vector of size n (be it with function search or with
function dic search ) in the worst case (for example, when the element x does not appear
in the sequence). Apart from operations of constant cost (arithmetic computations, com-
parisons and assignments between integers, vector accesses), exactly one call is made
over a vector of size half of that of the input. Therefore, the cost is determined by the
recurrence:
C (n) = C (n/2) + Θ(1),
which, by the master theorem of divisive recurrences, has solution C (n) = Θ(log(n)).

Proposed solution to problem 3

(a) It computes mn .
(b) The cost of the function is determined by the cost of the loop. Each iteration requires
time Θ(1), since only arithmetic operations and integer assignments are performed.
Therefore, the cost is proportional to the number of iterations. We observe that if y is
even, then y is reduced to half its value. And if y is odd with y > 1, then at the next
iteration the value y − 1 is considered, which is even, and then it is reduced to half its
value. Hence if n ≥ 1 the number of iterations is between 1 + ⌊log(n)⌋ and 1 + 2⌊log(n)⌋.
Altogether, the cost is Θ(log(n)).

Proposed solution to problem 4


√ √
5 +1 5− 1
(a) We have that φ − 1 = 2 −1= 2 , and then
√ √ √ √
5+1 5−1 ( 5 + 1)( 5 − 1) 5 − 1
φ · ( φ − 1) = · = = =1
2 2 4 4

Hence φ−1 = φ − 1.

(b) By induction over n:


• Base case n = 0: we have F (0) = 0, and

φn − (−φ)−n

1−1
F (n) = √ = √ = 0.
5
n =0 5

• Base case n = 1: we have F (1) = 1, and



φn − (−φ)−n φ + φ −1

5
F (n) = √ = √ = √ = 1.
5
n =1 5 5

• Inductive case n > 1: by induction hypothesis,

φn−2 − (−φ)−(n−2) φn−1 − (−φ)−(n−1)


F ( n ) = F ( n − 2) + F ( n − 1) = √ + √ =
5 5
Solutions to Mid Term Exams 165

φn−1 (φ−1 + 1) − (−φ)−(n−1) (−φ + 1) φn−1 · φ − (−φ)−(n−1) (−φ−1 )


= √ = √ =
5 5

φn − (−φ)−n
= √
5

(c) We have that


φn −(− φ) −n
F (n) √
5
1 − ( −φ21 )n 1
lim = lim = lim √ =√
n →+ ∞ φ n n →+ ∞ φ n n →+ ∞ 5 5

since φ > 1, φ2 > 1 and limn→+∞ ( −φ21 )n = 0. So F (n) = Θ(φn ).


166 Solutions to Mid Term Exams

Solution Midterm Exam EDA 20/04/2017

Proposed solution to problem 1

(a) Insertion sort has cost Θ(n) when the vector is already sorted, and cost Θ(n2 ) when it is
sorted backwards. So the average cost is:

log n log n
(1 − ) Θ( n ) + Θ(n2 ) = Θ(n − log n + n log n) = Θ(n log n)
n n

√ whether n is a prime number. The cost is determined by the loop,


(b) The function returns √
which makes O( n) iterations, each of which has constant cost. Thus the cost is O( n).
(c) Each of the numbers that are multiplied in n! are less than or equal to n. Since we
multiply n of them, we have n! ≤ nn for all n ≥ 1. So n! = O(nn ), taking n0 = 1 and
C = 1.
(d) Except for 1, all numbers that are multiplied in n! are greater than or equal to 2. Since
we multiply n − 1 of them, we have n! ≥ 2n−1 = 21 · 2n for all n ≥ 1. So n! = Ω(2n ), taking
n0 = 1 and C = 21 .

Proposed solution to problem 2

(a) A possible solution:


int top rec (const vector<int>& a, int l , int r) {
if ( l + 1 ≥ r) {
if (a[ l ] < a[r ]) return r ;
else return l ;
}
int m = ( l+r)/2;
if (a[m−1] > a[m]) return top rec(a , l , m−1);
if (a[m+1] > a[m]) return top rec (a , m+1, r );
return m;
}

int top (const vector<int>& a) {


return top rec (a , 0, a . size ()−1);
}

Let C (n) be the cost in time in the worst case of function top rec on a vector of size n. In
the worst case (for example, when the top is in one of the ends of the vector) a recursive
call will be made on a subvector of size n/2, in addition to operations of constant cost
(arithmetic computations, comparisons and assignments of integers, vector accesses). So
we have the recurrence C (n) = C (n/2) + Θ(1), which by the master theorem of divisive
recurrences has solution C (n) = Θ(log n).
(b) A possible solution that uses the function int top (const vector<int>& a) of the previous
exercise and the function binary search of STL:
Solutions to Mid Term Exams 167

bool search (const vector<int>& a, int x) {


int t = top(a );
int n = a. size ();
if ( binary search (a. begin (), a. begin () + t , x)) return true;
if ( binary search (a. rbegin (), a. rbegin () + n − t, x)) return true;
return false ;
}

In another possible solution, the previous search function can be replaced by:

bool bin search inc (const vector<int>& a, int l , int r , int x) {


if ( l > r) return false ;
int m = ( l+r)/2;
if (a[m] < x) return bin search inc (a , m+1, r, x );
if (a[m] > x) return bin search inc (a , l , m−1, x);
return true;
}

bool bin search dec (const vector<int>& a, int l , int r , int x) {


if ( l > r) return false ;
int m = ( l+r)/2;
if (a[m] < x) return bin search dec (a , l , m−1, x);
if (a[m] > x) return bin search dec (a , m+1, r, x );
return true;
}

bool search (const vector<int>& a, int x) {


int t = top(a );
int n = a. size ();
if ( bin search inc (a, 0, t −1, x)) return true;
if ( bin search dec (a, t , n−1, x)) return true;
return false ;
}

When function search searches in a vector of size n, in addition to calling function top,
one or two binary searches are made, each of which has cost O(log n), and also oper-
ations of constant cost. So the cost of search is O(log n) + O(log n) + O(1) = O(log n).
Moreover, if for example the top of the sequence is in one of the ends of the vector,
then the cost is Θ(log n) + O(log n) + O(1) = Θ(log n). So the cost in the worst case is
Θ(log n).

Proposed solution to problem 3

(a) After m calls to function reserve on an initially empty vector, the capacity of the vector
is of C (m) = Am elements. So the number of calls to reserve after n calls to push back is
the least m such that Am ≥ n, that is, ⌈ An ⌉. Since A is constant, m is Θ(n).
(b) By induction.
168 Solutions to Mid Term Exams

BA m − B B− B
• Base case: m = 0. We have that A −1 | m =0 = A −1 = 0 = C ( 0) .
• Inductive case: assuming that it is true for m, let us show it is also true for m + 1.
m
By induction hypothesis, C (m) = BAA−−1 B . Then:

BAm − B BAm+1 − AB + AB − B BAm+1 − B


C (m + 1) = AC (m) + B = A +B= =
A−1 A−1 A−1

(c) After m calls to function reserve on an initially empty vector, the capacity of the vector is
m
of C (m) = BAA−−1 B elements. So the number of calls to reserve after n calls to push back is
the least m such that BA m − B
A −1 ≥ n, that is, ⌈log A ( n( A−B1)+ B )⌉. Since A and B are constants,
m is Θ(log n).

Proposed solution to problem 4

(a) A possible solution:


int stable partition (int x, vector<int>& a) {
int n = a. size ();
vector<int> w(n);
int i = 0;
for (int y : a)
if (y ≤ x) {
w[i] = y;
++i;
}
int r = i −1;
for (int y : a)
if (y > x) {
w[i] = y;
++i;
}
for (int k = 0; k < n; ++k)
a[k] = w[k];

return r ;
}
The cost in time is Θ(n), since the vector is traversed 3 times, and each iteration of these
traversals only requires constant time. The cost in space of the auxiliary memory is
dominated by vector w, which has size n. Hence the cost in space is Θ(n).
(b) The function transposes the two subvectors of a from l to p and from p + 1 to r: if before
the call a[l..r] is Al , . . . , A p , A p+1, . . . , Ar , then after the call a[l..r] is A p+1 , . . . , Ar , Al , . . . , A p .
(c) Solution:
int stable partition (int x, vector<int>& a) {
return stable partition rec (x, a , 0, a . size ()−1);
}

int stable partition rec (int x, vector<int>& a, int l , int r) {


Solutions to Mid Term Exams 169

if ( l == r) {
if (a[ l ] ≤ x) return l ;
else return l −1;
}
int m = ( l+r)/2;
int p = stable partition rec (x, a , l , m);
int q = stable partition rec (x, a , m+1, r );
mystery(a , p+1, m, q );
return p+q−m;
}
Let C (n) be the cost of function stable partition rec on a vector of size n = r − l + 1 in
the worst case. On the one hand two recursive calls are made on vectors of size n/2. On
the other, the cost of the non-recursive work is dominated by function mystery, which
takes time which is linear in the size of the vector that is being transposed. Using the
hypothesis of the statement (which happens, for example, in a vector in which elements
smaller and bigger than x alternate successively), this vector has size Θ(n). So we have
the recurrence C (n) = 2C (n/2) + Θ(n), which by the master theorem of divisive recur-
rences has solution Θ(n log n). In conclusion, the cost of function stable partition on a
vector of size n in the worst case is Θ(n log n).
170 Solutions to Mid Term Exams

Solution Midterm Exam EDA 06/11/2017

Proposed solution to problem 1



(a) The cost is Θ(n n).
(b) The cost in the worst case and in the average case is Θ(n).

(c) Θ( n).
(d) Θ(n2 log n).
(e) Θ(2n ).

Proposed solution to problem 2

(a) The value b[y] counts the number of elements of the sequence a that are less than or
equal to y.
(b) A possible solution:
int median(int n, const vector<int>& b) {
int l = 0;
int r = b. size () − 1;
while (l 6= r−1) {
int q = ( l+r)/2;
if (2* b[q] < n) l = q;
else r = q;
}
return r ;
}
(c) At each iteration of the loop, the value r − l is reduced by half. As initially l = 0 and
r = m, we have that Θ(log m) iterations are performed. And since each iteration has
a constant cost (arithmetic operations with integers, vector accesses, etc.), we conclude
that the cost of the function is Θ(log m).

Proposed solution to problem 3

(a) A possible solution:


complex operator*(const complex& a, const complex& b) {
return {a. real * b. real − a.imag * b. imag, a . real * b.imag + a. imag * b. real };
}

complex exp(complex z, int n) {


if (n == 0) return {1, 0};
complex x = exp(z , n/2);
complex y = x*x;
if (n % 2 == 1) y = y*z ;
return y;
}
Solutions to Mid Term Exams 171

(b) The cost C (n) of the recursive function exp as a function of n is determined by the re-
currence C (n) = C (n/2) + Θ(1): a single recursive call is made over a problem of size
n/2, and the rest of the operations have constant cost. By applying the master theorem
of divisive recurrences, we have that the solution is C (n) = Θ(log n) as required.

Proposed solution to problem 4

(a) We have that

U (m) = T (2m ) = T (2m /2) + log(2m ) = T (2m−1 ) + log(2m ) = U (m − 1) + m

(b) By applying the master theorem of subtractive recurrences for solving the recurrence
U (m) = U (m − 1) + m, we have that U (m) = Θ(m2 ).
(c) As U (m) = Θ(m2 ) i U (m) = T (2m ), we have that T (n) = T (2log n ) = U (log n) = Θ((log n)2 ).
172 Solutions to Mid Term Exams

Solution Midterm Exam EDA 19/04/2018

Proposed solution to problem 1

(a) Function g grows faster:

2 2 2
f (n) nn n
log ( n ) lim
n
log ( n2n )
lim = lim 2n = lim 2 22n = 2 n→∞ 2 =0
n →∞ g( n ) n→∞ 2 n→∞

since
2
nn n2 2n 2 n
lim log( 2 n ) = lim (log( n ) − log(2 )) = lim ( n log n − 2 ) = − ∞
n→∞ 2 n→∞ n→∞

(b) The cost of the algorithm in the average case is Θ(n2 ):

1 1 1 1
· Θ( n4 ) + · Θ( n3 ) + (1 − 3 − ) · Θ( n ) = Θ( n ) + Θ( n2 ) + Θ( n ) = Θ( n2 )
n3 n n n

(c) By using the Master Theorem of divisive recurrences we have that a√= 2, b = 4, α =
log4 2 = 12 and k = 21 . So α = k, and therefore T (n) = Θ(nα · log n) = Θ( n · log n).

Proposed solution to problem 2

(a) The base case for k = 0 is true: A0 · x0 = x0 = x(0). For the inductive case, when k > 0,
we have by induction hypothesis that x(k − 1) = Ak−1 · x0 . So x(k) = A · x(k − 1) =
A · ( A k − 1 · x0 ) = ( A · A k − 1 ) · x0 = A k · x0 .
(b) In the first place Ak is computed using the algorithm of fast exponentiation in time
Θ(log k) (since n is constant). Then the result of multiplying Ak times x0 is returned,
which can be done in time Θ(1) (again, as n is constant). The cost in time of the algo-
rithm is then Θ(log k).

Proposed solution to problem 3

(a) x = x2 · 32n/3 + x1 · 3n/3 + x0 .

(b) x · y = x2 y2 · 34n/3 + ( x1 y2 + x2 y1 ) · 33n/3 + ( x0 y2 + x1 y1 + x2 y0 ) · 32n/3 + ( x1 y0 + x0 y1 ) ·


3n/3 + x0 y0 .

(c) x · y =
Solutions to Mid Term Exams 173

x2 y2 · 34n/3
+( x1 y2 + x2 y1 ) · 33n/3
+(( x0 + x1 + x2 ) · (y0 + y1 + y2 ) − x2 y2 − ( x1 y2 + x2 y1 ) − ( x1 y0 + x0 y1 ) − x0 y0 ) · 32n/3
+( x1 y0 + x0 y1 ) · 3n/3
+ x0 y0

We use 7 products.
(d) To compute the product of x and y of n digits, the algorithm computes recursively ( x0 +
x1 + x2 ) · (y0 + y1 + y2 ), x2 y2 , x1 y2 + x2 y1 , x1 y0 + x0 y1 and x0 y0 , which are products
of numbers of n/3 digits. Then x · y is computed using the equation of the previous
section. As numbers are represented in base 3, to multiply by a power of 3 consists
in adding zeroes to the right and can be done in time Θ(n). The involved additions
can also be done in time Θ(n). Therefore the cost T (n) satisfies the recurrence T (n) =
7T (n/3) + Θ(n), which has solution Θ(nlog3 7 ).

Proposed solution to problem 4

(a) We define function U (m) = T (bm ). Then T (n) = U (logb (n)). Moreover, we have:

U (m) = T (bm ) = T (bm /b) + Θ(logk (bm )) = T (bm−1 ) + Θ(mk logk (b)) =

= T ( b m − 1 ) + Θ ( m k ) = U ( m − 1) + Θ ( m k )
The Master Theorem of subtractive recurrences claims that if we have a recurrence of
the form U (m) = U (m − c) + Θ(mk ) with c > 0 and k ≥ 0, then U (m) = Θ(mk+1 ). So the
solution to the recurrence of the statement is T (n) = Θ((logb (n))k+1 ) = Θ(logk+1 n).

(b) A possible solution:


bool search (const vector<int>& a, int x, int l , int r) {
if ( l == r) return x == a[l ];
int m = ( l+r)/2;
auto beg = a . begin ();
if (a[m] < a[m+1])
return search (a , x, m+1, r) or binary search (beg + l , beg + m + 1, x );
else
return search (a , x, l , m) or binary search (beg + m+1, beg + r + 1, x );
}

bool search (const vector<int>& a, int x) {


return search (a , x, 0, a . size ()−1);
}
(c) The worst case takes place for instance when x does not appear in a. In this situation
the cost T (n) is described by the recurrence T (n) = T (n/2) + Θ(log n), as we make
one recursive call over a vector of size n2 , and the cost of the non-recursive work is
dominated by the binary search, which has cost Θ(log( n2 )) = Θ(log(n)). By applying
the first section we have that the solution is T (n) = Θ(log2 (n)).
174 Solutions to Mid Term Exams

Solution Midterm Exam EDA 05/11/2018

Proposed solution to problem 1

(a) The answers:

(1) (2) (3) (4) (5) (6) (7) (8) (9) (10)
TRUE X X X X X X
FALSE X X X X

Proposed solution to problem 2

(a) The cost in the worst case is Θ(n3 ). The worst case always happens.

(b) The cost in the best case is Θ(n2 ). The best case happens, for example, when the two
matrices only have true in their coefficients.

The cost in the worst case is Θ(n3 ). The worst case happens, for example, when the two
matrices only have false in their coefficients.

(c) The function considers the Boolean matrices as matrices of integers, in which false is
interpreted as 0 and true as 1. Then we apply Strassen’s algorithm for the product of
matrices. Let M be the resulting matrix. The coefficient of the i-th row and j-th column
of M is
n −1
mij = ∑ (aik · bkj ).
k=0

As the coefficients of the input matrices are 0 or 1, the product as integer numbers is the
same as the logical ∧ operation. So mij counts the number of pairs ( aik , bkj ) where both
aik and bkj are true at the same time. Therefore, to obtain the logical product we only
have to define pij as 1 if mij > 0, and 0 otherwise. The cost is dominated by Strassen’s
algorithm, which has cost Θ(nlog2 7 ) ≈ Θ(n2.8 ).

Proposed solution to problem 3


(a) Given an integer n ≥ 0, function mystery computes ⌊ n⌋.

(b) First of all we find the cost C ( N ) of the function mystery rec in terms of the size N =
r − l + 1 of the interval [l, r]. This cost follows the recurrence C ( N ) = C ( N/2) + Θ(1),
as at each call a recursive call is made on an interval with half the elements, and there is
additional non-recursive work with constant cost. According to the master theorem of
divisive recurrences, the solution to this recurrence is Θ(log N ). As mystery(n) consists
in calling mystery rec (n, 0, n+1), we can conclude that the cost of mystery(n) is Θ(log n).
Solutions to Mid Term Exams 175

Proposed solution to problem 4

(a) Θ(n)
(b) Θ(n2 )
(c) Θ(n log n)
(d) Θ(n log n)
(e) A possible solution:
void my sort(vector<int>& v) {
int n = v. size ();
double lim = n * log (n );
int c = 0;
for (int i = 1; i < n; ++i) {
int x = v[ i ];
int j ;
for ( j = i ; j > 0 and v[j − 1] > x; −−j) {
v[ j ] = v[ j − 1];
++c;
}
v[ j ] = x;
if (c > lim) {
merge sort (v );
return;
}
}
}
(f) First of all we observe that, as the outermost for loop makes n − 1 iterations, each of
which has cost Ω(1), the cost of the overall execution is Ω(n).
If for example the vector is already sorted in increasing order, then my sort behaves as
insertion sort: the innermost for loop is never entered, c is always 0, and merge sort is
not called. As each iteration of the outermost for loop has constant cost, the cost in this
case is Θ(n). So the cost of my sort in the best case is Θ(n).
To see the cost in the worst case, we distinguish two cases:
• Suppose that merge sort is not called. Then the cost is proportional to the final
value of variable c. As merge sort is not called, we have that c ≤ n ln n, and the cost
is O(n ln n) = O(n log n).
• Suppose that merge sort is eventually called. If it is called at the end of the first
iteration of the outermost for loop, then the cost is O(n) from the innermost for
loop plus Θ(n log n) of the merge sort. Altogether, the cost is Θ(n log n).
If merge sort is called at the end of the second, or third, etc. iteration of the out-
ermost for loop, then merge sort was not called at the previous iteration of the
outermost for loop. Moreover, in the last iteration c may have increased in i at
most, so when merge sort is called we have that n ln n < c ≤ i + n ln n ≤ n + n ln n ≤
n ln n + n ln n = 2n ln n (for n big enough), and hence c = Θ(n log n). Since the cost
of merge sort is Θ(n log n), altogether the cost is Θ(n log n).
176 Solutions to Mid Term Exams

The worst case happens for example when the vector is sorted backwards, that is, in
decreasing order. As in this case insertion sort has cost Θ(n2 ), at some point of the
execution of my sort the subprocedure merge sort will be called, and by the previous
reasoning the cost will be Θ(n log n).
5
Solutions to Lab Exams
178 Solutions to Lab Exams

Solution to Lab Exam EDA - shift 1 13/12/2010

Shift 1

Solution to problem 1

#include <iostream>
#include <vector>
#include <queue>
#include <cassert>

using namespace std;

const int N DIRS = 4;


const int di [N DIRS] = { 1, 0, −1, 0};
const int dj [N DIRS] = { 0, 1, 0, −1};

struct Pos {
int i , j ;
Pos(int ii = −1, int jj = −1) : i ( ii ), j ( jj ) { }
};

bool ok(int n, int m, int i , int j ) {


return
0 ≤ i and i < n and
0 ≤ j and j < m;
}

int search (const vector < vector<char> >& map, int n, int m, int i0 , int j0 ) {
const int MINFTY = −1;
vector< vector<int> > dist(n, vector<int> (m, MINFTY));
queue<Pos> q;
int max dist = MINFTY;
q.push(Pos(i0 , j0 ));
dist [ i0 ][ j0 ] = 0;
while (not q.empty()) {
Pos p = q. front ();
q.pop ();
int i = p. i ;
int j = p. j ;
for(int k = 0; k < N DIRS; ++k) {
int ii = i + di [k ];
int jj = j + dj [k ];
if (ok(n,m, ii , jj ) and map[ii][ jj ] 6= 'X' and dist [ ii ][ jj ] == MINFTY) {
q.push(Pos( ii , jj ));
dist [ ii ][ jj ] = 1 + dist [ i ][ j ];
if (map[ii ][ jj ] == ' t ' ) max dist = dist [ ii ][ jj ];
}
}
Solutions to Lab Exams 179

}
return max dist ;
}

int main(void) {
int n, m;
cin >> n >> m;
vector < vector<char> > map(n, vector<char>(m));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> map[i][j ];
int f , c ;
cin >> f >> c;
−−f;
−−c;
int dist = search (map, n, m, f , c );
if ( dist ≥ 0) cout << ”distancia maxima: ” << dist << endl;
else cout << ”no es pot arribar a cap tresor” << endl;
}

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

typedef vector<bool> Vec;


typedef vector<Vec > Mat;

void next(int i , int j , int n, int& ni, int& nj) {


if ( j < n−1) {
ni = i ;
nj = j+1;
}
else {
ni = i+1;
nj = 0;
}
}

const int N DIRS = 8;


const int DI[N DIRS] = { −1, −1, 0, 1, 1, 1, 0, −1};
const int DJ[N DIRS] = { 0, −1, −1, −1, 0, 1, 1, 1};

bool ok(int i , int j , int n) {


return
0 ≤ i and i < n and
180 Solutions to Lab Exams

0 ≤ j and j < n;
}

bool safe (int i , int j , int n, Mat& m) {


for (int k = 0; k < 8; ++k) {
int ii = i + DI[k ];
int jj = j + DJ[k ];
if (ok( ii , jj , n) and m[ii][ jj ]) return false ;
}
return true;
}

void escriu (int n, const Mat& m) {


for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j)
if (m[i][ j ]) cout << 'K';
else cout << ' . ' ;
cout << endl;
}
cout << ”−−−−−−−−−−” << endl;
}

void search (int i , int j , int n, int r , int s , Mat& m) {


if (s == r) escriu (n, m);
else if ( i 6= n) {
int ni , nj ;
next( i , j , n, ni , nj );
if ( safe ( i , j , n, m)) {
m[i][ j ] = true;
search (ni , nj , n, r , s+1, m);
}
m[i][ j ] = false ;
search (ni , nj , n, r , s , m);
}
}

int main(void) {
int n, r ;
cin >> n >> r;
Mat m(n, Vec(n, false ));
search (0, 0, n, r , 0, m);
}
Solutions to Lab Exams 181

Shift 2

Solution to problem 1

#include <iostream>
#include <string>
#include <map>

using namespace std;

typedef map<string, int>:: iterator Iterator ;

int main(void) {
map<string, int> bagmul;
string command;
while (cin >> command) {
if (command == ”store”) {
string word;
cin >> word;
pair < Iterator , bool> res = bagmul. insert ( pair <string,int>(word, 1));
if (not res . second) ++bagmul[word];
}
else if (command == ”delete”) {
string word;
cin >> word;
Iterator i = bagmul.find(word);
if ( i 6= bagmul.end()) {
if ( i −>second == 1) bagmul.erase ( i );
else −−bagmul[word];
}
}
else if (command == ”minimum?”) {
if (bagmul.empty()) cout << ”indefinite minimum” << endl;
else {
Iterator i = bagmul.begin ();
cout << ”minimum: ”
<< i−> first << ”, ”
<< i−>second << ” time(s)” << endl;
}
}
else {
if (bagmul.empty()) cout << ”indefinite maximum” << endl;
else {
Iterator i = bagmul.end ();
−−i;
cout << ”maximum: ”
<< i−>first << ”, ”
<< i−>second << ” time(s)” << endl;
}
182 Solutions to Lab Exams

}
}
}

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

typedef vector<char> CVec;


typedef vector<CVec> CMat;
typedef vector<bool> BVec;
typedef vector<BVec> BMat;

const int N DIRS = 4;


const int DR[N DIRS] = { 0,−1, 0, 1};
const int DC[N DIRS] = { 1, 0,−1, 0};

struct Point {
int r , c ;
Point(int rr , int cc) : r( rr ), c(cc ) { }
};

bool ok(int r , int c , int n, int m) {


return
0 ≤ r and r < n and
0 ≤ c and c < m;
}

void search (int re , int ce , int n, int m, const CMat& t, vector<Point>& v, BMat& seen) {
Point p = v.back ();
if (p. r == re and p.c == ce) {
for (int i = 0; i < v. size (); ++i)
cout << t[v[ i ]. r ][ v[ i ]. c ];
cout << endl;
}
else {
for (int k = 0; k < N DIRS; ++k) {
int rr = p. r + DR[k];
int cc = p.c + DC[k];
if (ok( rr , cc , n, m) and not seen[rr ][ cc ]) {
seen [ rr ][ cc] = true;
v.push back(Point( rr , cc ));
search ( re , ce , n, m, t , v, seen );
v.pop back ();
seen [ rr ][ cc] = false ;
Solutions to Lab Exams 183

}
}
}
}

int main(void) {
int n, m;
cin >> n >> m;
CMat t (n, CVec(m));
BMat seen(n, BVec(m, false ));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> t[i ][ j ];
int ri , ci , re , ce ;
cin >> ri >> ci >> re >> ce;
seen [ ri ][ ci ] = true;
vector<Point> v(1, Point( ri , ci ));
search ( re , ce , n, m, t , v, seen );
}
184 Solutions to Lab Exams

Solution to Lab Exam EDA 19/5/2011

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

struct Point {
int r , c ;
Point(int rr , int cc) : r( rr ), c(cc ) {}
};

bool ok(int n, int m, const Point& p) {


return
0 ≤ p.r and p. r < n and
0 ≤ p.c and p. c < m;
}

const int N DIRS KNIGHT = 8;


const int DR KNIGHT[8] = {−2, −1, 2, 1, −2, −1, 2, 1};
const int DC KNIGHT[8] = {−1, −2, −1, −2, 1, 2, 1, 2};

const int N DIRS BISHOP = 4;


const int DR BISHOP[4] = { 1, −1, 1, −1};
const int DC BISHOP[4] = { 1, 1, −1, −1};

int dfs (int n, int m, const Point& p,


vector< vector<char> >& map, vector< vector<bool> >& marked,
const int N DIRS, const int DR[], const int DC[]) {
int s = 0;
marked[p.r ][ p.c] = true;
for (int i = 0; i < N DIRS; ++i) {
Point q(p. r + DR[i], p.c + DC[i]);
if (ok(n,m,q) and map[q.r][q. c] 6= 'T' and not marked[q.r ][ q. c ])
s += dfs (n, m, q, map, marked, N DIRS, DR, DC);
}
if ( ' 0' ≤ map[p.r][p. c] and map[p.r][p. c] ≤ '9' ) {
s += map[p.r][p. c] − '0' ;
map[p.r][p.c] = ' . ' ;
}
return s ;
}

int main(void) {
int n, m;
while (cin >> n >> m) {
Solutions to Lab Exams 185

vector<Point> knights, bishops ;


vector< vector<char> > map(n, vector<char>(m));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j) {
cin >> map[i][j ];
switch(map[i][j ]) {
case ' K': knights . push back(Point( i , j )); break;
case ' B' : bishops . push back(Point( i , j )); break;
};
}
int s = 0;
vector< vector<bool> > marked knight(n, vector<bool>(m, false));
for (int k = 0; k < knights . size (); ++k) {
Point p = knights [k ];
if (not marked knight[p. r ][ p.c ])
s += dfs (n, m, p, map, marked knight, N DIRS KNIGHT, DR KNIGHT, DC KNIGHT);
}
vector< vector<bool> > marked bishop(n, vector<bool>(m, false));
for (int k = 0; k < bishops . size (); ++k) {
Point p = bishops [k ];
if (not marked bishop[p. r ][ p.c ])
s += dfs (n, m, p, map, marked bishop , N DIRS BISHOP, DR BISHOP, DC BISHOP);
}
cout << s << endl;
}
}

Solution to problem 2

#include <iostream>
#include <set>

using namespace std;

typedef long long int lint ;

int main(void) {

lint suma = 0;
set <lint> selec ;
set <lint> resta ;

int n;
cin >> n;
string op;
lint val ;
while (cin >> op >> val) {
if (op == ”deixar”) {
186 Solutions to Lab Exams

if ( selec . size () < n) {


selec . insert ( val );
suma += val;
}
else {
lint min = *( selec . begin ());
if (min < val) {
selec . insert ( val );
selec . erase ( selec . begin ());
suma = suma + val − min;
resta . insert (min);
}
else resta . insert ( val );
}
}
else {
if (*( selec . begin ()) ≤ val) {
selec . erase ( val );
suma −= val;
if ( resta . size () > 0) {
set <lint>:: iterator it = resta . end ();
−−it;
selec . insert (* it );
suma += * it ;
resta . erase ( it );
}
}
else resta . erase ( val );
}
cout << suma << endl;
}
}
Solutions to Lab Exams 187

Solution to Lab Exam EDA 13/12/2011

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

typedef vector<char> VC;


typedef vector<VC> MC;
typedef vector<bool> VB;
typedef vector<VB> MB;

const int N DIRS = 4;


const int DI[N DIRS] = { 1, 0, −1, 0};
const int DJ[N DIRS] = { 0, 1, 0, −1};

bool ok(int n, int m, int i , int j ) {


return
0 ≤ i and i < n and
0 ≤ j and j < m;
}

int search (const MC& map, int n, int m, int i , int j , MB& marked) {
int t = 0;
if (map[i][ j ] == ' t ' ) ++t;
marked[i ][ j ] = true;
for (int k = 0; k < N DIRS; ++k) {
int ii = i + DI[k ];
int jj = j + DJ[k ];
if (ok(n, m, ii , jj ) and map[ii][ jj ] 6= 'X' and not marked[ii ][ jj ])
t += search (map, n, m, ii , jj , marked);
}
return t ;
}

int main(void) {
int n, m;
cin >> n >> m;
MC map(n, VC(m));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> map[i][j ];
int f , c ;
cin >> f >> c;

MB marked(n, VB(m, false));


188 Solutions to Lab Exams

cout << search(map, n, m, f −1, c−1, marked) << endl;


}

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

void b(int k , int n, string& s) {


if (k == n) cout << s << endl;
else {
s[k] = ' A'; b(k+1, n, s );
s[k] = ' C'; b(k+1, n, s );
s[k] = ' G'; b(k+1, n, s );
s[k] = ' T' ; b(k+1, n, s );
}
}

int main() {
int n;
cin >> n;
string s(n, ' X' );
b (0, n, s );
}
Solutions to Lab Exams 189

Solution to Lab Exam EDA 14/05/2012

Solution to problem 1

#include<iostream>
#include<string>
#include<map>

using namespace std;

typedef map<string,string>::iterator ite ;

int main() {
string s ;
map<string,string> liats ;
while(cin >> s) {
if (s == ”info”) {
cout << ”PARELLES:” << endl;
for ( ite it = liats . begin (); it 6= liats . end (); ++it)
if ( it −>second 6= ”” and it−>first < it−>second)
cout << it −>first << ” ” << it −>second << endl;
cout << ”SOLS:” << endl;
for ( ite it = liats . begin (); it 6= liats . end (); ++it)
if ( it −>second == ””)
cout << it −>first << endl;
cout << ”−−−−−−−−−−” << endl;
}
else {
string x, y;
cin >> x >> y;
if ( liats [x] 6= ””) liats [ liats [x]] = ””;
if ( liats [y] 6= ””) liats [ liats [y]] = ””;
liats [x] = y;
liats [y] = x;
}
}
}

Solution to problem 2

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>

using namespace std;


190 Solutions to Lab Exams

const int xf [8] = {−1,−1,−1,0,0,1,1,1};


const int yf [8] = {−1,0,1,−1,1,−1,0,1};
const int x[4] = {0,0,1,−1};
const int y[4] = {1,−1,0,0};

bool cerca bolet (vector<vector<char> >& M, pair<int,int> p) {


queue<pair<int, int> > Q;
if (M[p. first ][ p.second] == 'X') return false ;
M[p. first ][ p.second] = ' X' ; Q.push(p);
while (not Q.empty()) {
pair <int,int> q = Q.front (); Q.pop ();
for (int i = 0; i < 4; ++i) {
int u = q. first + x[ i ];
int v = q. second + y[ i ];
if (M[u][v] == 'B' ) return true;
if (M[u][v] 6= 'X') {
M[u][v] = ' X' ;
Q.push(make pair(u,v ));
}
}
}
return false ;
}

int main() {
int f , c ;
while (cin >> f >> c) {
vector<vector<char> > M(f, vector<char> (c));
pair <int, int> p;
queue<pair<int,int> > F;
for (int i = 0; i < f ; ++i) {
for (int j = 0; j < c; ++j) {
cin >> M[i][j ];
if (M[i][j ] == 'P' ) {p. first = i ; p.second = j ;}
if (M[i][j ] == 'F' ) F.push(make pair( i , j ));
}
}
while (not F.empty()) {
int i = (F. front ()). first ;
int j = (F. front ()). second ;
F.pop ();
for (int k = 0; k < 8; ++k) M[i+xf[k ]][ j+yf[k ]] = ' X' ;
}
if ( cerca bolet (M,p)) cout << ”si” << endl;
else cout << ”no” << endl;
}
}
Solutions to Lab Exams 191

Solution to Lab Exam EDA 29/11/2012

Solution to problem 1

#include <iostream>
#include <sstream>
#include <vector>
#include <queue>

using namespace std;

typedef vector< queue<string> > VQS;

void read queues (int n, VQS& v) {


v = VQS(n);
for (int k = 0; k < n; ++k) {
string line ;
getline (cin, line );
istringstream in( line );
string name;
while (in >> name) v[k].push(name);
}
}

void process exits (VQS& v) {


cout << ”SORTIDES” << endl;
cout << ”−−−−−−−−” << endl;

string op;
while (cin >> op) {
if (op == ”SURT”) {
int idx ;
cin >> idx;
−−idx;
if (0 ≤ idx and idx < v. size () and not v[idx ]. empty()) {
cout << v[idx ]. front () << endl;
v[idx ]. pop ();
}
}
else {
string name;
int idx ;
cin >> name >> idx;
−−idx;
if (0 ≤ idx and idx < v. size ())
v[idx ]. push(name);
}
}
192 Solutions to Lab Exams

cout << endl;


}

void write final contents (VQS& v) {


cout << ”CONTINGUTS FINALS” << endl;
cout << ”−−−−−−−−−−−−−−−−−” << endl;
for (int k = 0; k < v. size (); ++k) {
cout << ”cua ” << k+1 << ”:”;
while (not v[k ]. empty()) {
cout << ' ' << v[k]. front ();
v[k ]. pop ();
}
cout << endl;
}
}

int main() {
int n;
cin >> n;
string line ;
getline (cin, line ); // Read empty line.

VQS v;
read queues (n, v );
process exits (v );
write final contents (v );
}

Solution to problem 2

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

typedef vector<int> VI;


typedef vector<VI> VVI;

void compute topological ordering (const VVI& g, VI& indeg, VI& ord) {
int n = g. size ();
priority queue <int, vector<int>, greater<int> > pq;
for (int u = 0; u < n; ++u)
if (indeg[u] == 0) pq.push(u);

ord = VI(n);
int cnt = 0;
while (not pq.empty()) {
Solutions to Lab Exams 193

int u = pq. top ();


pq.pop ();
ord[cnt] = u;
++cnt;
for (int k = 0; k < g[u]. size (); ++k) {
int v = g[u][k ];
−−indeg[v];
if (indeg[v] == 0) pq.push(v );
}
}
}

void write (const VI& v) {


cout << v[0];
for (int k = 1; k < v. size (); ++k)
cout << ' ' << v[k];
cout << endl;
}

int main() {
int n, m;
while (cin >> n >> m) {
VVI g(n);
VI indeg(n, 0);
for (int k = 0; k < m; ++k) {
int u, v;
cin >> u >> v;
g[u ]. push back(v );
++indeg[v];
}
VI ord ;
compute topological ordering (g, indeg , ord );
write (ord );
}
}
194 Solutions to Lab Exams

Solution to Lab Exam EDA 22/5/2013

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> VI;

int n, m;
VI div ;

bool ok(int y) {
for (int i = 0; i < m; ++i)
if (y % div[i ] == 0)
return false ;
return true;
}

void backtracking (int k , int x) {


if (k == n) cout << x << endl;
else {
for (int v = 0; v ≤ 9; ++v) {
int y = 10*x + v;
if (ok(y)) backtracking (k+1, y );
}
}
}

int main() {
while (cin >> n >> m) {
div = VI(m);
for (int i = 0; i < m; ++i)
cin >> div[i ];
backtracking (0, 0);
cout << ”−−−−−−−−−−” << endl;
}
}

Solution to problem 2

#include <iostream>
#include <vector>
#include <queue>
Solutions to Lab Exams 195

using namespace std;

typedef vector<char> VC; typedef vector< int> VI;


typedef vector< VC > VVC; typedef vector< VI > VVI;

typedef pair<int,int> P;

const int DF[] = {1, 1,−1,−1, 2, 2,−2,−2};


const int DC[] = {2,−2, 2,−2, 1,−1, 1,−1};

const int oo = 200 * 200;

bool ok(int i , int j , int n, int m, const VVC& t) {


return i ≥ 0 and i < n and j ≥ 0 and j < m and t[i ][ j ] 6= 'X' ;
}

int distance (int f0 , int c0 , const VVC& t) {


int n = t . size ();
int m = t [0]. size ();
VVI d(n, VI(m, +oo ));
queue<P> q;
q.push(P(f0 , c0 ));
d[f0 ][ c0] = 0;
while (not q.empty()) {
P p = q. front ();
q.pop ();
int f = p. first ;
int c = p.second ;
if ( t [ f ][ c] == 'p' ) return d[ f ][ c ];
for (int k = 0; k < 8; ++k) {
int i = f + DF[k];
int j = c + DC[k];
if (ok( i , j , n, m, t ) and d[i ][ j ] == +oo) {
q.push(P(i , j ));
d[ i ][ j ] = d[ f ][ c] + 1;
}
}
}
return +oo;
}

int main() {
int n, m;
while (cin >> n >> m) {
VVC t(n, VC(m));

for (int i = 0; i < n; ++i)


for (int j = 0; j < m; ++j)
cin >> t[i ][ j ];
196 Solutions to Lab Exams

int f0 , c0;
cin >> f0 >> c0;
int dist = distance ( f0 −1, c0−1, t );
if ( dist == +oo) cout << ”no” << endl;
else cout << dist << endl;
}
}
Solutions to Lab Exams 197

Solution to Lab Exam EDA 4/12/2013

Solution to problem 1

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int UNDEF = −1;


const int N DIRS = 4;
const int DI[N DIRS] = { 1, 0, −1, 0};
const int DJ[N DIRS] = { 0, 1, 0, −1};

struct Pos {
int i , j ;
Pos(int ii , int jj ) : i ( ii ), j ( jj ) { }
};

bool ok(int n, int m, int i , int j ) {


return
0 ≤ i and i < n and
0 ≤ j and j < m;
}

int bfs (const vector < vector<char> >& map, int i0, int j0) {
int n = map . size ();
int m = map[0]. size ();
queue<Pos> q;
q.push( Pos(i0 , j0 ) );
vector< vector<int> > dist(n, vector<int>(m, UNDEF));
dist [ i0 ][ j0 ] = 0;
while (not q.empty()) {
Pos p = q. front ();
q.pop ();
int i = p. i ;
int j = p. j ;
if (map[i][ j ] == ' t ' ) return dist [ i ][ j ];
else {
for(int k = 0; k < N DIRS; ++k) {
int ii = i + DI[k ];
int jj = j + DJ[k ];
if (ok(n, m, ii , jj ) and map[ii][ jj ] 6= 'X' and dist [ ii ][ jj ] == UNDEF) {
q. push( Pos( ii , jj ) );
dist [ ii ][ jj ] = 1 + dist [ i ][ j ];
}
}
198 Solutions to Lab Exams

}
}
return UNDEF;
}

int main(void) {

int n, m;
cin >> n >> m;

vector < vector<char> > map(n, vector<char>(m));


for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> map[i][j ];

int f , c ;
cin >> f >> c;

int dist = bfs (map, f −1, c−1);


if ( dist > 0) cout << ”distancia minima: ” << dist << endl;
else cout << ”no es pot arribar a cap tresor” << endl;
}

Solution to problem 2

#include <iostream>
#include <vector>
#include <map>
#include <assert.h>

using namespace std;

typedef map<string,int> MSI;


typedef vector<string> VS;
typedef vector<bool> VB;
typedef vector<int> VI;
typedef vector<VI> VVI;

int n outputs , n inputs ;


VVI gdir, ginv;
MSI s2v;
VS v2s;

int string2vertex (const string& s) {


auto i = s2v. find (s );
if ( i 6= s2v.end ())
return i −>second;
Solutions to Lab Exams 199

else {
int v = v2s. size ();
v2s.push back(s );
s2v. insert (make pair(s , v ));
return v;
}
}

int main() {

n outputs = n inputs = 0;

string token ;

cin >> token;


assert ( token == ”OUTPUT”);
while (cin >> token and token 6= ”END”) {
++n outputs;
string2vertex ( token );
}

cin >> token;


assert ( token == ”INPUT”);
while (cin >> token and token 6= ”END”) {
++n inputs;
string2vertex ( token );
}

while (cin >> token and token 6= ”END”) {

string s ;
cin >> s;
int ov = string2vertex (s );
if (ov+1 > gdir. size ()) gdir . resize (ov+1);

cin >> s;
int iv1 = string2vertex (s );
if (iv1 + 1 > ginv. size ()) ginv. resize (iv1 + 1);

if ( token == ”NOT”) {
gdir [ov ]. push back(iv1 );
ginv[iv1 ]. push back(ov );
}
else {
cin >> s;
int iv2 = string2vertex (s );
if (iv2 + 1 > ginv. size ()) ginv. resize (iv2 + 1);
if ( token == ”AND”) {
gdir [ov ]. push back( min(iv1, iv2) );
200 Solutions to Lab Exams

gdir [ov ]. push back( max(iv1,iv2) );


}
else {
gdir [ov ]. push back( max(iv1,iv2) );
gdir [ov ]. push back( min(iv1, iv2) );
}
ginv[iv1 ]. push back(ov );
ginv[iv2 ]. push back(ov );
}
}

int n = gdir . size ();


VI ddir (n, 0);
for (int v = 0; v < n; ++v)
ddir [v] = gdir [v ]. size ();

VI bag;
for (int v = n outputs ; v < n inputs + n outputs ; ++v)
bag.push back(v );

VI ord ;
while (not bag.empty()) {
int v = bag.back ();
ord . push back(v );
bag.pop back ();
for (auto w : ginv[v]) {
−−ddir[w];
if ( ddir [w] == 0)
bag.push back(w);
}
}

VB val(n );
while (cin >> token) {
val [ n outputs ] = (token == ”T”);
for (int v = n outputs+1; v < n inputs + n outputs ; ++v) {
cin >> token;
val [v] = (token == ”T”);
}

for (auto v : ord) {


if ( gdir [v ]. size () == 1) {
val [v] = not val [ gdir [v ][0]];
}
else if ( gdir [v ]. size () == 2) {
int iv1 = gdir [v ][0];
int iv2 = gdir [v ][1];
if (iv1 < iv2) val [v] = val [iv1] and val[iv2 ];
else val [v] = val [iv1] or val [iv2 ];
Solutions to Lab Exams 201

}
}
cout << (val [0] ? ' T' : ' F' );
for (int v = 1; v < n outputs; ++v)
cout << ' ' << (val[v] ? ' T' : ' F' );
cout << endl;
}
}
202 Solutions to Lab Exams

Solution to Lab Exam EDA 19/5/2014

Solution to problem 1

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef vector<bool> VB;


typedef vector<int> VI;
typedef vector<VI> VVI;

void path(int xi , int xf , const VI& p) {


if ( xf == xi) cout << xi;
else {
path( xi , p[xf ], p );
cout << ” ” << xf;
}
}

void bfs (const VVI& g, int xi , int xf ) {


int n = g. size ();
VI p(n, −1);
VB mkd(n, false );
VI cur, pos ;

cur. push back( xi );


mkd[xi] = true;
while (not cur. empty()) {
for (int x : cur) {
if (x == xf) {
path( xi , xf , p );
cout << endl;
return;
}
for (int y : g[x])
if (not mkd[y]) {
pos .push back(y );
mkd[y] = true;
p[y] = x;
}
}
swap(pos, cur );
}
}
Solutions to Lab Exams 203

int main() {
int n, m;
while (cin >> n >> m) {
VVI g(n);
for (int k = 0; k < m; ++k) {
int x, y;
cin >> x >> y;
g[x ]. push back(y );
}
for (int x = 0; x < n; ++x)
sort (g[x ]. begin (), g[x ]. end ());

bfs (g, 0, n−1);


}
}

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

typedef vector<bool> VB;

void bt(int k , int n, string& w, VB& mkd) {


if (k == n) cout << w << endl;
else {
for (int i = 0; i < n; ++i)
if (not mkd[i] and (k == 0 or ' a' + i 6= w[k−1] + 1)) {
mkd[i] = true;
w[k] = ' a' + i ;
bt (k+1, n, w, mkd);
mkd[i] = false ;
}
}
}

int main() {
int n;
cin >> n;
string w(n, ' a' );
VB mkd(n, false );
bt (0, n, w, mkd);
}
204 Solutions to Lab Exams

Solution to Lab Exam EDA 22/12/2014

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

typedef vector<bool> VB;


typedef vector<int> VI;
typedef vector<VI> VVI;

const int UNDEF = −1;

bool cyclic (int x, const VVI& g, VB& mkd, VI& par) {


if (mkd[x]) return true;
mkd[x] = true;
for (int y : g[x])
if (par[x] 6= y) {
par[y] = x;
if ( cyclic (y, g, mkd, par )) return true;
}
return false ;
}

int nombre arbres(const VVI& g) {


int n = g. size ();
VB mkd(n, false );
VI par(n, UNDEF);
int n arb = 0;
for (int x = 0; x < n; ++x) {
if (not mkd[x]) {
if ( cyclic (x, g, mkd, par )) return UNDEF;
else ++n arb;
}
}
return n arb ;
}

int main() {
int n, m;
while (cin >> n >> m) {
VVI g(n);
for (int k = 0; k < m; ++k) {
int x, y;
cin >> x >> y;
g[x ]. push back(y );
Solutions to Lab Exams 205

g[y ]. push back(x );


}
int n arb = nombre arbres(g );
if (n arb == UNDEF) cout << ”no” << endl;
else cout << n arb << endl;
}
}

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> VI;

int bt (int k , const VI& m, int x, int sum par, int max und) {
if (sum par > x or sum par + max und < x) return 0;
if (k == m.size ()) return 1;
int cnt = 0;
for (int v = 0; v ≤ 2; ++v)
cnt += bt(k+1, m, x, sum par + v*m[k], max und − 2*m[k]);
return cnt ;
}

int main() {
int x, n;
while (cin >> x >> n) {
VI m(n);
int s = 0;
for (int k = 0; k < n; ++k) {
cin >> m[k];
s += m[k];
}
cout << bt(0, m, x, 0, 2* s) << endl;
}
}
206 Solutions to Lab Exams

Solution to Lab Exam EDA 25/05/2015

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

typedef vector<char> VC;


typedef vector<VC> VVC;

int bt (int i , int j , VVC& sol, int curr) {


int n = sol . size ();
int m = sol [0]. size ();
if ( i == n) return curr ;
int next i , next j ;
if ( j == m−1) {
next i = i+1;
next j = 0;
}
else {
next i = i ;
next j = j+1;
}

sol [ i ][ j ] = ' L' ;


int new lols = 0;
if ( i ≥ 2 and sol[ i −1][ j ] == 'O' and sol[ i −2][ j ] == 'L' ) ++new lols;
if ( j ≥ 2 and sol[ i ][ j −1] == 'O' and sol[ i ][ j −2] == 'L' ) ++new lols;
if ( i ≥ 2 and j ≥ 2 and sol[ i −1][j−1] == 'O' and sol[ i −2][j−2] == 'L') ++new lols;
if ( i ≥ 2 and j+2 < m and sol[i −1][j+1] == 'O' and sol[ i −2][j+2] == 'L' ) ++new lols;
int nl = bt ( next i , next j , sol , curr + new lols );

sol [ i ][ j ] = ' O';


int no = bt ( next i , next j , sol , curr );

return max(nl, no );
}

int main() {
int n, m;
while (cin >> n >> m) {
VVC sol(n, VC(m));
cout << bt(0, 0, sol , 0) << endl;
}
}
Solutions to Lab Exams 207

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

typedef vector<char> VC;


typedef vector<VC> VVC;
typedef vector<bool> VB;
typedef vector<VB> VVB;

bool ok(int i , int j , const VVC& t) {


int n = t . size ();
int m = t [0]. size ();
return i ≥ 0 and i < n and j ≥ 0 and j < m and t[i ][ j ] 6= 'X' ;
}

const int di [] = {0, 1, 0, −1};


const int dj [] = {1, 0, −1, 0};

bool possible (int i ini , int j ini , int i fin , int j fin , const VVC& t, VVB& mkd) {
if (mkd[ i ini ][ j ini ]) return false ;
mkd[ i ini ][ j ini ] = true;
if ( i ini == i fin and j ini == j fin ) return true;
for (int k = 0; k < 4; ++k) {
int i = i ini + di [k ];
int j = j ini + dj [k ];
if (ok( i , j , t ) and possible ( i , j , i fin , j fin , t , mkd)) return true;
}
return false ;
}

int main() {
int n, m;
while (cin >> n >> m) {
VVC t(n, VC(m));
int i ini , j ini , i fin , j fin ;
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> t[i ][ j ];

for (int i = 0; i < n; ++i)


for (int j = 0; j < m; ++j)
if ( t [ i ][ j ] == ' I ' ) {
i ini = i ;
j ini = j ;
}
else if ( t [ i ][ j ] == 'F' ) {
208 Solutions to Lab Exams

i fin = i ;
j fin = j ;
}
else if ( t [ i ][ j ] == 'M') {
t [ i ][ j ] = ' X' ;
if ( i −1 ≥ 0 and t[i−1][ j ] 6= 'M') t [ i −1][ j ] = ' X' ;
if ( i+1 < n and t[ i+1][ j ] 6= 'M') t [ i+1][ j ] = ' X' ;
if ( j −1 ≥ 0 and t[ i ][ j −1] 6= 'M') t [ i ][ j −1] = 'X' ;
if ( j+1 < m and t[ i ][ j+1] 6= 'M') t [ i ][ j+1] = ' X' ;
}

VVB mkd(n, VB(m, false));


if ( possible ( i ini , j ini , i fin , j fin , t , mkd)) cout << ”SI” << endl;
else cout << ”NO” << endl;
}
}
Solutions to Lab Exams 209

Solution to Lab Exam EDA 22/12/2015

Solution to problem 1

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const vector<pair<int, int>> DIRS = { {1, 0}, {−1, 0}, {0, 1}, {0, −1} };
const int UNDEF = −1;

int dist 2on tresor mes llunya (int i0 , int j0 , vector<vector<char>>& mapa) {
int max dist = UNDEF;
int max dist2 = UNDEF;
queue<pair< pair<int, int>, int >> q;
q.push({{i0 , j0 }, 0});
mapa[i0][ j0 ] = ' X' ;
while (not q.empty()) {
int i = q. front (). first . first ;
int j = q. front (). first . second ;
int d = q. front (). second ;
q.pop ();
for (auto dir : DIRS) {
int ii = i + dir . first ;
int jj = j + dir . second ;
if (mapa[ii ][ jj ] 6= 'X') {
if (mapa[ii ][ jj ] == ' t ' ) {
max dist2 = max dist ;
max dist = d+1;
}
q.push({{ ii , jj }, d+1});
mapa[ii ][ jj ] = ' X' ;
}
}
}
return max dist2 ;
}

int main() {
int n, m;
cin >> n >> m;
vector<vector<char>> mapa(n+2, vector<char>(m+2, 'X'));
for (int i = 1; i ≤ n; ++i)
for (int j = 1; j ≤ m; ++j)
cin >> mapa[i][j ];
210 Solutions to Lab Exams

int f , c ;
cin >> f >> c;

int d2 = dist 2on tresor mes llunya ( f , c , mapa);


if (d2 == UNDEF) cout << ”no es pot arribar a dos o mes tresors” << endl;
else cout << ”segona distancia maxima: ” << d2 << endl;
}

Solution to problem 2

#include <iostream>
#include <vector>

using namespace std;

void escriu (int f , int c , const vector<int>& col) {


for (int i = 0; i < f ; ++i) {
for (int j = 0; j < c; ++j)
if ( col [ i ] == j) cout << ”R”;
else cout << ”.”;
cout << endl;
}
cout << endl;
}

void torres (int f , int c , int i , vector<int>& col, vector<bool>& marked) {


if ( i == f) escriu ( f , c , col );
else
for (int j = 0; j < c; ++j)
if (not marked[j ]) {
col [ i ] = j ;
marked[j] = true;
torres ( f , c , i+1, col , marked);
marked[j] = false ;
}
}

int main() {
int f , c ;
cin >> f >> c;
vector<int> col( f );
vector<bool> marked(c, false);
torres ( f , c , 0, col , marked);
}
Solutions to Lab Exams 211

Solution to Lab Exam EDA 19/05/2016

Solution to problem 1

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

typedef pair<int,int> P;

int main(void) {
int n, m;
while (cin >> n >> m) {
vector<vector<P>> g(n);
for (int k = 0; k < m; ++k) {
int x, y, c ;
cin >> x >> y >> c;
−−x;
−−y;
g[x ]. push back(P(c, y ));
g[y ]. push back(P(c, x ));
}
vector<bool> mkd(n, false);
mkd[0] = true;
priority queue <P, vector<P>, greater<P> > pq;
for (P x : g [0]) pq.push(x );
int sz = 1;
int sum = 0;
while (sz < n) {
int c = pq. top (). first ;
int x = pq. top (). second ;
pq.pop ();
if (not mkd[x]) {
mkd[x] = true;
for (P y : g[x]) pq.push(y );
sum += c;
++sz;
}
}
cout << sum << endl;
}
}

Solution to problem 2
212 Solutions to Lab Exams

#include <vector>

using namespace std;

// Pre: l ≤ r, x < v[r].


// Return the smallest i s.t. l ≤ i ≤ r and x < v[i].
int rightmost (double x, const vector<double>& v, int l, int r) {
if ( l == r) return l ;
int m = (l+r)/2;
if (x < v[m]) return rightmost (x, v, l , m);
else return rightmost (x, v, m+1, r );
}

int rightmost (double x, const vector<double>& v) {


return rightmost (x, v, 0, v. size ());
}
Solutions to Lab Exams 213

Solution to Lab Exam EDA 15/12/2016

Shift 1

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

vector<vector<int>> su;
vector<vector<bool>> r mkd, c mkd;
vector<vector<vector<bool>>> s mkd;

void write () {
cout << endl;
for (int i = 0; i < 9; ++i) {
cout << su[i ][0] + 1;
for (int j = 1; j < 9; ++j)
cout << ' ' << su[i ][ j ] + 1;
cout << endl;
}
}

bool fill (int i , int j ) {


if ( i == 9) return true;
if ( j == 9) return fill ( i+1, 0);
if (su[ i ][ j ] 6= −1) return fill ( i , j +1);
for (int v = 0; v < 9; ++v)
if (not r mkd[i ][ v] and not c mkd[j][v] and not s mkd[i/3][j/3][v]) {
r mkd[i ][ v] = c mkd[j ][ v] = s mkd[i/3][ j /3][v] = true;
su[ i ][ j ] = v;
if ( fill ( i , j+1)) return true;
r mkd[i ][ v] = c mkd[j ][ v] = s mkd[i/3][ j /3][v] = false ;
}
su[ i ][ j ] = −1;
return false ;
}

int main() {
su = vector<vector<int>>(9, vector<int>(9));
int n;
cin >> n;
cout << n << endl;
while (n−−) {
r mkd = c mkd = vector<vector<bool>>(9, vector<bool>(9, false));
s mkd = vector<vector<vector<bool>>>(3, vector<vector<bool>>(3, vector<bool>(9, false)));
for (int i = 0; i < 9; ++i)
214 Solutions to Lab Exams

for (int j = 0; j < 9; ++j) {


char c ;
cin >> c;
if (c == ' . ' ) su[ i ][ j ] = −1;
else {
int v = c − '1 ' ;
r mkd[i ][ v] = c mkd[j ][ v] = s mkd[i/3][ j/3][v] = true;
su[ i ][ j ] = v;
}
}
if ( fill (0, 0)) write ();
}
}

Solution to problem 2

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

bool search (const vector<int>& a, int l , int r , int x) {


if ( l+1 == r) return a[ l ] == x or a[r] == x;
int m = (l+r)/2;
if (a[m] ≥ a[l ]) {
if (a[ l ] ≤ x and x ≤ a[m]) {
return binary search (a . begin()+ l , a . begin()+m+1, x);
}
else return search (a , m, r , x );
}
else {
if (a[m] ≤ x and x ≤ a[r]) {
return binary search (a . begin()+m, a . begin()+r+1, x );
}
else return search (a , l , m, x );
}
}

bool search (int x, const vector<int>& a) {


return search (a , 0, a . size ()−1, x );
}
Solutions to Lab Exams 215

Shift 2

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

int m, n;
vector<int> l;

void gen(int i , int pos) {


if (pos ≥ −m/2 and pos ≤ m/2) {
if ( i == n) cout << pos << endl;
else {
gen( i+1, pos+l[ i ]);
gen( i+1, pos−l[i ]);
}
}
}

int main() {
cin >> m >> n;
l = vector<int>(n);
for (int& x : l ) cin >> x;
gen (0, 0);
}

Solution to problem 2

#include <iostream>

using namespace std;

typedef int Matrix [2][2];

void product(int m, const Matrix& a, const Matrix& b, Matrix& c) {


for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j) {
c[ i ][ j ] = 0;
for (int k = 0; k < 2; ++k)
c[ i ][ j ] = (c[ i ][ j ] + a[ i ][ k] * b[k ][ j ]) % m;
}
}

void identity (Matrix& b) {


216 Solutions to Lab Exams

b [0][0] = b [1][1] = 1;
b [0][1] = b [1][0] = 0;
}

void power(int n, int m, const Matrix& a, Matrix& b) {

if (n == 0)
identity (b );
else {
if (n%2 == 0) {
Matrix c ;
power(n/2, m, a , c );
product(m, c , c , b );
}
else {
Matrix c , d;
power(n/2, m, a , c );
product(m, c , c , d );
product(m, a , d, b );
}
}
}

int main() {
Matrix a ;
a [0][0] = 1; a [0][1] = 1;
a [1][0] = 1; a [1][1] = 0;
int n, m;
while (cin >> n >> m) {
Matrix b;
power(n, m, a , b );
cout << b[1][0] << endl;
}
}
Solutions to Lab Exams 217

Solution to Lab Exam EDA 25/05/2017

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

enum Letter {CON = 0, VOC};

void g(int k , int n, vector<string>& let, string& sol , vector<vector<bool>>& mkd) {


if (k == 2*n) cout << sol << endl;
else {
int k2 = k%2;
for (int i = 0; i < n; ++i)
if (not mkd[k2][i ]) {
sol [k] = let [k2][ i ];
mkd[k2][i ] = true;
g(k+1, n, let , sol , mkd);
mkd[k2][i ] = false ;
}
}
}

int main() {
int n;
cin >> n;
vector<vector<bool>> mkd(2, vector<bool>(n, false));
vector<string> let (2);
cin >> let [CON] >> let[VOC];
string sol (2* n, ' ' ); // Need a char for filling.
g (0, n, let , sol , mkd);
}

Solution to problem 2

#include <iostream>
#include <vector>
#include <unordered set>
#include <queue>

using namespace std;

const int UND = −1;

int main() {
218 Solutions to Lab Exams

int n, t ;
while (cin >> n >> t) {
vector<unordered set<int>> g(n);
while (−−t ≥ 0) {
int s ;
cin >> s;
vector<int> pub(s);
for (int i = 0; i < s; ++i)
cin >> pub[i ];

for (int i = 0; i < s; ++i)


for (int j = i+1; j < s; ++j) {
int u = pub[i ];
int v = pub[j ];
g[u ]. insert (v );
g[v ]. insert (u );
}
}
vector<int> dst(n, UND);
queue<int> q;
dst [0] = 0;
q.push (0);
while (not q.empty()) {
int u = q. front ();
q.pop ();
for (int v : g[u])
if ( dst [v] == UND) {
dst [v] = dst [u] + 1;
q. push(v );
}
}
for (int u = 0; u < n; ++u) {
cout << u << ” : ”;
if ( dst [u] == UND) cout << ”no”;
else cout << dst[u ];
cout << endl;
}
for (int k = 0; k < 10; ++k) cout << ”−”;
cout << endl;
}
}
Solutions to Lab Exams 219

Solution to Lab Exam EDA 25/05/2017

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

void write (int n, int p, const vector<string>& s, vector<int>& sol) {


for (int j = 0; j < p; ++j) {
cout << ”subset ” << j+1 << ”: {”;
string aux = ””;
for (int i = 0; i < n; ++i)
if ( sol [ i ] == j) {
cout << aux << s[i ];
aux = ”,”;
}
cout << ”}” << endl;
}
cout << endl;
}

void g(int k , int n, int p, const vector<string>& s, vector<int>& sol) {


if (k == n) write (n, p, s , sol );
else
for (int i = 0; i < p; ++i) {
sol [k] = i ;
g(k+1, n, p, s , sol );
}
}

int main() {
int n, p;
cin >> n;
vector<string> s(n);
for (auto& x : s) cin >> x;
cin >> p;
vector<int> sol(n);
g (0, n, p, s , sol );
}

Solution to problem 2

#include <iostream>
#include <vector>
#include <queue>
220 Solutions to Lab Exams

using namespace std;

typedef pair<int,int> P;

int main() {
int n, m;
while (cin >> n >> m) {
vector< vector<P> > g(n);
int tot = 0;
for (int k = 0; k < m; ++k) {
int x, y, c ;
cin >> x >> y >> c;
g[x ]. push back({c , y });
g[y ]. push back({c , x });
tot += c;
}
vector<bool> mkd(n, false);
mkd[0] = true;
priority queue <P, vector<P>, greater<P> > pq;
for (P p : g [0])
pq.push(p );
int sz = 1;
int sum = 0;
while (sz < n) {
int c = pq. top (). first ;
int x = pq. top (). second ;
pq.pop ();
if (not mkd[x]) {
mkd[x] = true;
for (P p : g[x])
pq.push(p );
sum += c;
++sz;
}
}
cout << tot − sum << endl;
}
}
Solutions to Lab Exams 221

Solution to Lab Exam EDA 28/05/2018

Solution to problem 1

#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> VI;


typedef vector<VI > VVI;

int n, m;
VVI g;
VI c ;

const int UNDEF = −1;

// Returns true if no conflict is found.


bool propagate (int x, int col ) {
if (c[x] == UNDEF) {
c[x] = col ;
for (int y: g[x])
if (not propagate (y, 1−col)) return false ;
return true;
}
else return c[x] == col ;
}

bool two colorable (int x) {


if (x == n) return true;
if (c[x] == UNDEF) return propagate(x, 0) and two colorable (x+1);
else return two colorable (x+1);
}

int main() {
while (cin >> n >> m) {
g = VVI(n);
for (int k = 0; k < m; ++k) {
int x, y;
cin >> x >> y;
g[x ]. push back(y );
g[y ]. push back(x );
}
c = VI(n, UNDEF);
if ( two colorable (0)) cout << ”yes” << endl;
else cout << ”no” << endl;
}
}
222 Solutions to Lab Exams

Solution to problem 2

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Permutation {

vector<int> v;

public:

Permutation(int n) : v( n ) { }
Permutation(const Permutation& s) : v(s . v) { }

Permutation& operator = (const Permutation& s) {


v = s . v;
return * this ;
}

int& operator []( int i ) { return v[ i ]; }


int operator []( int i ) const { return v[ i ]; }

Permutation& operator *= (const Permutation& s) {


for (int i = 0; i < v. size (); ++i)
v[ i ] = s[v[ i ]];
return * this ;
}

void pow(int k) {
if (k == 0)
for (int i = 0; i < v. size (); ++i)
v[ i ] = i ;
else {
Permutation s = * this ;
s . pow(k/2);
if (k % 2 == 0) {
* this = s ;
* this *= s ;
}
else {
* this *= s ;
* this *= s ;
}
}
}
};
Solutions to Lab Exams 223

int main() {
int n;
while (cin >> n) {
Permutation p(n );
for (int i = 0; i < n; ++i) {
cin >> p[i ];
}
int k ;
cin >> k;
p.pow(k);

for (int x = 0; x < n; ++x)


cout << (x == 0 ? ”” : ” ”) << p[x];
cout << endl;
}
}
224 Solutions to Lab Exams

Solution to Lab Exam EDA 03/12/2018

Solution to problem 1

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int top(const vector<int>& v, int l , int r) {


if ( l + 1 ≥ r) {
if (v[ l ] < v[r ]) return r ;
else return l ;
}
int m = (l+r)/2;
if (v[m−1] > v[m]) return top(v, l , m−1);
if (v[m+1] > v[m]) return top(v, m+1, r );
return m;
}

bool bin search (bool inc , const vector<int>& v, int l , int r , int x) {
if ( l == r) return v[ l ] == x;
int m = (l+r)/2;
bool cond;
if ( inc ) cond = (x ≤ v[m]);
else cond = (x ≥ v[m]);
if (cond) return bin search ( inc , v, l , m, x );
else return bin search ( inc , v, m+1, r, x );
}

bool search (int x, const vector<int>& v) {


int n = v. size ();
int t = top (v, 0, n−1);
return bin search (true, v, 0, t , x) or bin search ( false , v, t , n−1, x);
}

Solution to problem 2

#include <iostream>
#include <queue>
#include <climits>

using namespace std;


using P = pair<int,int>;

const int oo = INT MAX;


Solutions to Lab Exams 225

int cost (const vector<vector<P>>& g, const vector<int>& z, int a, int b) {


int n = g. size ();
vector<int> dist(n, +oo);
priority queue <P, vector<P>, greater<P>> pq;
dist [a] = 0;
pq.push({0, a });
while (not pq.empty()) {
auto t = pq. top ();
pq.pop ();
int d = t . first ;
int u = t . second ;
if (d == dist [u]) {
if (u == b) return dist [b ];
for (auto e : g[u]) {
int v = e . first ;
int w = e . second ;
int dv = dist [u] + w + (v == b ? 0 : z[v ]);
if ( dist [v] > dv) {
dist [v] = dv;
pq.push({dv, v });
}
}
}
}
return +oo;
}

int main() {
int n, m;
cin >> n >> m;
vector<int> z(n);
for (int& x : z) cin >> x;
vector<vector<P>> g(n);
while (m−−) {
int u, v, w;
cin >> u >> v >> w;
g[u ]. push back({v, w});
g[v ]. push back({u, w});
}
int a , b;
while (cin >> a >> b) {
int c = cost (g, z , a , b );
cout << ”c(” << a << ”,” << b << ”) = ”;
if (c == +oo ) cout << ”+oo” << endl;
else cout << c << endl;
}
}
6
Solutions to Final Exams
228 Solutions to Final Exams

Solution of the Final EDA Exam 08/06/2016


Proposed solution to problem 1

(a) The master theorem for dividing recurrences claims that if we have a recurrence of the
form T (n) = aT (n/b) + Θ(nk ) with a > 0, b > 1 and k ≥ 0, then, letting α = logb a,

k
 Θ( n )
 if α < k,
T (n) = Θ(nk log n) if α = k,

Θ( n α ) if α > k.

(b) 2
(c) priority queue <T>’s are implemented with max-heaps. If there existed a function
T& top ();
then a user of the class could modify the root of the heap and break the invariant that
each node is greater than or equal to its children.

Proposed solution to problem 2

(a) Yes
(b) No (leaves must be black)
(c) No (the children of a red node must be black)
(d) Yes
(e) No (it must be a binary search tree)
(f) No (the number of black nodes in a path from the root to a leaf must be constant)

Proposed solution to problem 3

(a) Let C (n) be the cost of the algorithm in the worst case as a function of n. Then:
• If s ≥ 21 : C (n) = C (sn) + Θ(1)

• If s ≤ 21 : C (n) = C ((1 − s)n) + Θ(1)


(b) The worst case takes place, for instance:
• if s ≥ 12 , when x < v[l ].

• if s ≤ 12 , when x > v[r].


(c) We can solve the recurrences separately, or notice that
n
C (n) = C (max(s, 1 − s)n) + Θ(1) = C ( 1 ) + Θ ( 1)
max( s,1− s )

As 0 < s < 1, we have 0 < max(s, 1 − s) < 1, and so max(1s,1−s) > 1. By applying the
master theorem for dividing recurrences we have that α = k = 0, and therefore the cost
is Θ(log n) (independently of s).
Solutions to Final Exams 229

Proposed solution to problem 4

(a) A possible solution:


#include <limits>

const int oo = numeric limits <int>::max();

int minimum cost(const vector<vector<pair<int,int>>>& G, int x, int y) {


vector<int> cost(G.size (), +oo);
cost [x] = 0;
deque<int> dq;
dq.push back(x );
while (not dq.empty()) {
int u = dq. front ();
dq. pop front ();
if (u == y) return cost [y ];
for (auto p : G[u]) {
int v = p. first ;
int w = p.second ;
if ( cost [v] > cost [u] + w) {
cost [v] = cost [u] + w;
if (w == 0) dq. push front (v );
else dq.push back(v );
}} }
return −1;
}
(b) There is a cost that is proportional to the number of vertices (initialization of the vector
of costs). But the cost of the loop is proportional to the number of edges that are visited
(being thus the worst case when all edges are visited). In total the cost is Θ(|V | + | E|).
(c) Θ((|V | + | E|) log |V |)

Proposed solution to problem 4

(a) A possible solution:


bool ok(const vector<int>& s, const set<pair<int,int>>& D) {
for (auto d : D)
if (s[d. first ] == s[d.second ])
return false ;
return true;
}

bool has solution (int k , vector<int>& s, const inp DISEQUALITIES& e) {


if (k == e.n) return ok(s , e .D);
for (int v = e . l ; v ≤ e.u; ++v) {
s[k] = v;
if ( has solution (k+1, s , e )) return true;
}
return false ;
230 Solutions to Final Exams

bool has solution (const inp DISEQUALITIES& e) {


vector<int> s(e.n);
return has solution (0, s , e );
}
(b) When there is no solution, the algorithm considers each of the (u − l + 1)n possible
assignments of the n variables to the values in [l, u]. For each of these assignments,
work is performed with cost Ω(1). Hence, the cost in the worst case is Ω((u − l + 1)n ).
(c) A possible solution:
inp DISEQUALITIES reduction(const inp COLORING& ec) {
inp DISEQUALITIES ed;
ed . l = 1;
ed . u = ec . c ;
ed . n = ec . G. size ();
for (int u = 0; u < ec.G. size (); ++u)
for (int v : ec .G[u])
if (u < v)
ed . D. insert ({u, v });
return ed ;
}
(d) No. By the previous exercise we have that, as COLORING is NP-hard, then so is DIS-
EQUALITIES. Thus, if there were a polynomial algorithm for solving DISEQUALITIES,
we would have P = NP, and we would have solved a long-standing open problem in
theoretical computer science.
Solutions to Final Exams 231

Solution of the Final EDA Exam 12/01/2017

Proposed solution to problem 1

(a) (0.25 pts.) A graph with n vertices has O(n2 ) edges.


(b) (0.25 pts.) A connected graph with n vertices has Ω(n) edges.
(c) (0.25 pts.) A complete graph with n vertices has Ω(n2 ) edges.
(d) (0.25 pts.) A min-heap with n vertices has Θ(n) leaves.
(e) (0.25 pts.) A binary search tree with n vertices has height Ω(log n).
(f) (0.25 pts.) A binary search tree with n vertices has height O(n).
(g) (0.25 pts.) An AVL tree with n vertices has height Ω(log n).
(h) (0.25 pts.) An AVL tree with n vertices has height O(log n).

Proposed solution to problem 2

(a) Breadth-first search.


(b) Dijkstra’s algorithm.
(c) Bellman-Ford’s algorithm.
(d) There cannot be any cycle with negative weight in the graph.
(e) By induction over the number of arcs of the path.
• Base case: If the path has not arc, the source vertex u is the same as the target vertex
v. So in this case we have that ωπ (c) = ω (c) = 0. Since ω (c) − π (u) + π (v) = 0,
what we wanted to prove holds.
• Inductive case: Assume that the path has k arcs, that is, is of the form (u0 , u1 , . . . , uk ),
where u0 = u and uk = v. As u1 , . . . , uk is a path from u1 to uk with k − 1 arcs, we can
apply the induction hypothesis. So ωπ (u1 , . . . , uk ) = ω (u1 , . . . , uk ) − π (u1 ) + π (uk ).
But

ω π ( u0 , . . . , u k ) = ω π ( u0 , u1 ) + ω π ( u1 , . . . , u k )
= ω π ( u0 , u1 ) + ω ( u1 , . . . , u k ) − π ( u1 ) + π ( u k )
= ω ( u0 , u1 ) − π ( u0 ) + π ( u1 ) + ω ( u1 , . . . , u k ) − π ( u1 ) + π ( u k )
= ω ( u0 , u1 ) − π ( u0 ) + ω ( u1 , . . . , u k ) + π ( u k )
= ω ( u0 , . . . , u k ) − π ( u0 ) + π ( u k )

(f) If π is a potential, then the reduced weights ωπ are non-negative. So we can apply
Dijkstra’s algorithm to compute the distances with weights ωπ from s to all vertices.
Then we can compute the distances with weights ω using the following observation: if
u, v ∈ V i c is the minimum path with weights ω from u to v (which exists by hypothesis),
then c is the minimum path with weights ωπ from u to v and ω (c) = ωπ (c) + π (u) −
π ( v).
232 Solutions to Final Exams

Proposed solution to problem 3


n
(a) If M is an n × n matrix, function matrix mystery(const matrix& M) computes M ∑i=1 i , or
n ( n +1 )
equivalently, M 2 .
(b) The product of two matrices n × n, which is computed by function aux, takes Θ(n3 )
time. Since Θ(n) iterations are performed, and in each of them two matrix products are
computed with cost Θ(n3 ), in total the cost is Θ(n4 ).
(c) A possible solution:
matrix exp(const matrix& M, int k) {
if (k == 1) return M;
matrix P = exp(M, k/2);
if (k % 2 == 0) return aux(P, P);
else return aux(aux(P, P), M);
}

matrix mystery(const matrix& M) {


int n = M.size ();
return exp(M, n*(n+1)/2);
}
Fast exponentiation makes Θ(log(n(n + 1)/2)) = Θ(log(n)) matrix products, each of
which takes Θ(n3 ) time. In total, the cost is Θ(n3 log n).

Proposed solution to problem 4

(a) The witness is p.


(b) The code of the verifier is between lines 4 and 16.
(c) A possible solution:
bool ham2 rec(const vector<vector<int>>& G, int k, int u, vector<int>& next) {
int n = G. size ();
if (k == n)
return find (G[u].begin (), G[u].end (), 0) 6= G[u].end();

for (int v : G[u])


if (next[v] == −1) {
next[u] = v;
if (ham2 rec(G, k+1, v, next )) return true;
next[u] = −1;
}
return false ;
}

bool ham2(const vector<vector<int>>& G) {


int n = G. size ();
vector<int> next(n, −1);
return ham2 rec(G, 1, 0, next );
}
Solutions to Final Exams 233

(d) One can replace the call

return find (G[u].begin (), G[u].end (), 0) 6= G[u].end();


by

return not G[u].empty() and G[u][0] == 0;


(e) If G is not connected then it cannot be Hamiltonian. In this case the function only needs
to return false.
234 Solutions to Final Exams

Solution of the Final EDA Exam 09/06/2017

Proposed solution to problem 1

(a) The resulting max-heap is:

79

55 73

36 52 45 71

18 12 13

(b) To prove that P ⊆ co-NP we only need to see that if L is a problem from class P, then its
complement L belongs to NP. But if L is from P then there is a deterministic polynomial
algorithm A that decides L. Let us consider now the algorithm A that does the same as
A, but returns 1 when A returns 0, and returns 1 when A returns 0. Then A decides L,
and since A takes polynomial time, we have L ∈ P ⊆ NP.
(c) The cost C (n) of f in function of n follows the recurrence

C (n) = 3C (n/3) + Θ(1)

as there are 3 recursive calls on subvectors of size n/3 and additionally operations of
constant cost are performed. By the Master Theorem of Divisive Recurrences, the solu-
tion to the recurrence is C (n) = Θ(n).
(d) It is not true. For example, n2n = (nn )2 grows asymptotically faster than nn .

Proposed solution to problem 2

We must use a dictionary with integer keys implemented with a hash table, and a vector
which is initially empty that will contain the intersection.
First of all we pass over A and add all its elements to the dictionary. We make n insertions
to the dictionary, each of which takes time O(1) on average. So the first pass costs O(n) on
average.
In the second place we pass over B and, for each of its elements, we check if it already
belongs to the dictionary. If so, the element is added to the vector of the intersection with a
push back. Otherwise nothing is done. Hence we make m lookups to the dictionary, each of
which takes time O(1) on average. Since each push back takes constant time, the cost of the
second pass is O(m) on average.
In total, the cost is O(n + m) on average.

Proposed solution to problem 3

(a) The filled table is:


A B C D E F G H
level : depth : 4
0 1 1 1 4 2 0 3
Solutions to Final Exams 235

(b) The filled table is:


(1) (2) (3) (4)
TRUE X X
FALSE X X
(c) A possible solution:
vector<int> levels(const vector<vector<int>>& G) {
int n = G. size ();
vector<int> lvl(n, −1), pred(n, 0);

for (int u = 0; u < n; ++u)


for (int v : G[u])
++pred[v];

queue<int> Q;
for (int u = 0; u < n; ++u)
if (pred[u] == 0) {
Q.push(u);
lvl [u] = 0;
}

while (not Q.empty()) {


int u = Q.front (); Q.pop ();
for (int v : G[u]) {
−−pred[v];
lvl [v] = max(lvl[v ], lvl [u]+1);
if (pred[v] == 0) Q.push(v);
} }
return lvl ;
}
The construction of the vectors has cost Θ(n). The first loop has cost Θ(n + m). The
second loop has cost Θ(n). The third loop has cost Θ(n + m). In total the cost is Θ(n +
m ).

Proposed solution to problem 4

void write (const vector<int>& p, int n) {


for (int k = 0; k < n; ++k) cout << ” ” << p[k];
cout << endl;
}

void generate (int k , int n, vector<int>& p, vector<bool>& used) {


if (k == n) write (p, n );
else {
for (int i = 0; i < n; ++i)
if (not used[ i ] and k 6= i) {
used[ i ] = true;
p[k] = i ;
generate (k+1, n, p, used );
236 Solutions to Final Exams

used[ i ] = false ;
}
}
};

void generate all (int n) {


vector<int> p(n);
vector<bool> used(n, false);
generate (0, n, p, used );
}
Solutions to Final Exams 237

Solution of the Final EDA Exam 19/01/2018

Proposed solution to problem 1

(a) A possible solution:


void shift down (vector<int>& v, int i) {
int n = v. size ()−1;
int c = 2* i ;
if (c ≤ n) {
if (c+1 ≤ n and v[c+1] < v[c]) c++;
if (v[ i ] > v[c ]) {
swap(v[i ], v[c ]);
shift down (v, c );
} } }
(b) A possible solution:
void update (vector<int>& v, int i, int x) {
int y = v[ i ];
v[ i ] = x;
if (y < x) shift down (v, i );
else shift up ( v, i );
}

Proposed solution to problem 2

int n, k ;
vector<int> perm;
vector<bool> used;

void write () {
cout << perm[1];
for (int i = 2; i ≤ n; ++i) cout << ' ' << perm[i];
cout << endl;
}

void generate (int i , int lm, int mx) {


if (lm > k or n − i + 1 + lm < k) return;
if ( i == n+1) write ();
else {
for (int j = 1; j ≤ n; ++j)
if (not used[ j ]) {
used[ j ] = true;
perm[i] = j ;
if ( j > mx) generate( i+1, lm+1, j );
else generate ( i+1, lm, mx);
used[ j ] = false ;
}
}
238 Solutions to Final Exams

int main() {
cin >> n >> k;
perm = vector< int>(n+1);
used = vector<bool>(n+1, false);
generate (1, 0, 0);
}

Proposed solution to problem 3

(a) Given a string s of size n, function mystery computes the evaluation of s as a polynomial
in x: ∑in=−01 s[i ] · xi .
The value 0 would not be adequate for x if one wanted to use mystery as a hash function
because the function would always return s[0]; in other words, all strings that start with
the same character would have the same hash value.
(b) The answers:
(1) (2) (3) (4)
TRUE X X
FALSE X X
(c) The value returned by find(2) is 0. The value returned by find(9) is 5.
(d) In the worst case, the searched value is strictly greater than all values in the vector.
Hence at each recursive call the algorithm chooses the larger of the two parts, which
is 23 of the size of the interval [l, · · · , r]. Moreover, apart from the recursive call only
operations of constant cost are performed. So, if n = r − l + 1, the cost T (n) in the worst
case is determined by the recurrence T (n) = T ( 32 n) + Θ(1). By applying the master
theorem of divisive recurrences, we have that the solution to the recurrence is Θ(log n).

Proposed solution to problem 4

(a) The composition is:

2
1 3

0
6
4
5

(b) A possible solution:


matrix comp(const matrix& G1, const matrix& G2) {
int n = G1.size ();
matrix C(n, vector<int>(n, false ));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
Solutions to Final Exams 239

for (int k = 0; k < n and not C[i][ j ]; ++k)


C[i ][ j ] = G1[i][ k] and G2[k][j ];
return C;
}
In the worst case (for example, when the graphs G1 and G2 are empty) the three loops go
over the values from 0 to |V | − 1. As each iteration of the innermost loop has constant
cost, in total the cost in the worst case is Θ(|V |3 ).
(c) An alternative way of obtaining the adjacency matrix C of the composition would be
to compute the product P of the adjacency matrices of G1 and G2 as matrices of integer
numbers, and then take C [i ][ j] = 1 if and only if P[i ][ j] > 0.
As the product of matrices can be efficiently computed by using Strassen’s algorithm in
time Θ(|V |log2 7 ), this would be the cost of the resulting algorithm.
240 Solutions to Final Exams

Solution of the Final EDA Exam 20/06/2018

Proposed solution to problem 1

(a) priority queue <T>’s are implemented with max-heaps. If there existed a function

T& top ();

then a user of the class could modify the root of the heap and break the invariant that
each node is greater than or equal to its children.

(b)

A 0
B 110
C 10 A
D 111
C

B D

(c)

f s

c j r v

a d i m q u y

h x z

(d)

79

55 73

36 52 45 71

18 12 13
Solutions to Final Exams 241

Proposed solution to problem 2

(a) We define function U (m) = T (bm ). Then T (n) = U (logb (n)). Moreover, we have:

U (m) = T (bm ) = T (bm /b) + Θ(logk (bm )) = T (bm−1 ) + Θ(mk logk (b)) =

= T ( b m − 1 ) + Θ ( m k ) = U ( m − 1) + Θ ( m k )
The Master Theorem of subtractive recurrences claims that if we have a recurrence of
the form U (m) = U (m − c) + Θ(mk ) with c > 0 and k ≥ 0, then U (m) = Θ(mk+1 ). So the
solution to the recurrence of the statement is T (n) = Θ((logb (n))k+1 ) = Θ(logk+1 n).

(b) A possible solution:


bool search (const vector<int>& a, int x, int l , int r) {
if ( l == r) return x == a[l ];
int m = ( l+r)/2;
auto beg = a . begin ();
if (a[m] < a[m+1])
return search (a , x, m+1, r) or binary search (beg + l , beg + m + 1, x );
else
return search (a , x, l , m) or binary search (beg + m+1, beg + r + 1, x );
}

bool search (const vector<int>& a, int x) {


return search (a , x, 0, a . size ()−1);
}
(c) The worst case takes place for instance when x does not appear in a. In this situation
the cost T (n) is described by the recurrence T (n) = T (n/2) + Θ(log n), as we make
one recursive call over a vector of size n2 , and the cost of the non-recursive work is
dominated by the binary search, which has cost Θ(log( n2 )) = Θ(log(n)). By applying
the first section we have that the solution is T (n) = Θ(log2 (n)).

Proposed solution to problem 3

(a) A possible solution is:


bool two col aux(const vector<vector<int>>& g, int u, vector<bool>& col,
vector<bool>& marked, bool is red) {
col [u] = is red ;
marked[u] = true;
for (int v : g[u]) {
if (not marked[v]) {
if (not two col aux (g, v, col , marked, not is red )) return false ;
}
else if ( col [v] == col [u]) return false ;
}
return true;
}
242 Solutions to Final Exams

(b) The problem of 3-colorability is NP-complete. Therefore, if the claim in the forum were
right, we would have a polynomial-time algorithm that solved an NP-complete prob-
lem, and so P = NP. Since up to now the problem of whether P = NP is still open (and,
moreover, the dominant conjecture is that it is false), what is said in the forum is not
plausible.

Proposed solution to problem 4


✞ ☎ ✞ ☎ ✞ ☎

sum chosen + sum rest - a[k] >= l ✆ ✝
sum chosen + a[k] <= u ✆
✝ ✆
(a) sols(0, 0, s)

(b) It is only required to swap the recursive calls: that is, swap the two ifs (together with
their corresponding bodies) inside of the else.
Solutions to Final Exams 243

Solution of the Final EDA Exam 14/01/2019

Proposed solution to problem 1

(a) The resulting AVL tree:

35

25 50

12 30 40 70

10 31 65 86

(b) The resulting max-heap:

52

45 29

36 13 23 21

18 12

(c) Θ(n)

(d) Θ( n log n)

(e) Θ( n)
(f) The residual network:
1

v1 v3
4 3 3

s 1 2 2 t
2
6 1
v2 v4
1

Proposed solution to problem 2

(a) The function mystery computes the product of the polynomial p by the monomial c · xk .
Its cost in time is Θ(n + k).
244 Solutions to Final Exams

(b) The type unordered map<int,int> can be implemented with hash tables.

A way of completing the code:


polynomial mystery(const polynomial& p, int c , int k) {
polynomial q;
for (auto mon : p)
q[mon. first + k] = c * mon.second;
return q;
}
The cost of the function is dominated by the cost of the loop. Let m = p.size(). We do m
iterations, and in each of them the most expensive operation is to access to a pair of the
dictionary of q. Each access to this dictionary has cost O(1) in the average case. Hence
the cost in the average case is at most O(m).

(c) The cost of the function is Θ(n).

(d) A possible solution (similar to Karatsuba’s algorithm):


polynomial operator*(const polynomial& p, const polynomial& q) {
int n = p. size ();
if (n == 1) return polynomial (1, p[0]* q [0]);
int n2 = n/2;

polynomial p0(n2), p1(n2);


for (int k = 0; k < n2; ++k) p0[k] = p[k ];
for (int k = n2; k < n; ++k) p1[k − n2] = p[k ];

polynomial q0(n2), q1(n2);


for (int k = 0; k < n2; ++k) q0[k] = q[k ];
for (int k = n2; k < n; ++k) q1[k − n2] = q[k ];

polynomial p0 q0 = p0 * q0;
polynomial p1 q1 = p1 * q1;
polynomial p1 q0 plus p0 q1 = (( p0 + p1) * (q0 + q1)) +
mystery(p0 q0 + p1 q1, −1, 0);

return p0 q0 +
mystery(p1 q0 plus p0 q1 , 1, n2) +
mystery(p1 q1, 1, n );
}
The function makes 3 recursive calls over polynomials of size Θ(n/2). Moreover, the
non-recursive work (additions, calls to function mystery) has cost Θ(n). If we call T (n)
the cost of the function in terms of n, then we obtain the recurrence T (n) = 3T (n/2) +
Θ(n). By applying the master theorem of divisive recurrences we obtain that the cost is
T (n) = Θ(nlog 3 ), which is better than Θ(n2 ).

Proposed solution to problem 3

(a) The efficiency bug consists is that every time we choose a new subset, we scan the whole
vector S again, without considering the previously chosen subsets. This means that we
Solutions to Final Exams 245

can take the same subset several times, or consider different permutations of the same
collection of subsets.

A possible way of fixing the code is to add a parameter that is the index of the first subset
that we need to consider in the following choice:
bool set cover rec (int f , int K, int N, const vector<set<int>>& S,
vector<int>& w, int c) {
if (c == N) return true;
if (K == 0) return false ;
for (int i = f ; i < S. size (); ++i) {
for (int x : S[i ]) {
if (w[x] == 0) ++c;
++w[x];
}
if ( set cover rec ( i+1, K−1, N, S, w, c )) return true;
for (int x : S[i ]) {
−−w[x];
if (w[x] == 0) −−c;
}
}
return false ;
}

bool set cover (int K, int N, const vector<set<int>>& S) {


vector<int> w(N, 0);
return set cover rec (0, K, N, S, w, 0);
}

(b) Let us see the function g defines a reduction from VERTEX-COVER to SET-COVER.
Clearly it takes polynomial time in the size of the input of VERTEX-COVER. It remains
to be seen that an input (K, G ) of VERTEX-COVER is positive if and only if g(K, G ) =
(K, N, S) is also positive for SET-COVER.
If (K, G ) is positive for VERTEX-COVER then there is a vertex cover W ⊆ V with |W | ≤
K. We define T = {Su | u ∈ W }. Then | T | ≤ K. Now let i be such that 0 ≤ i < N. Then the
edge ei = {u, v} satisfies that i ∈ Su , i ∈ Sv . Moreover, as W is a cover, u ∈ W or v ∈ W. If
u ∈ W then Su ∈ T and therefore we have a subset of T that includes i. The case v ∈ W is
analogous. Hence T is a subset cover of {0, . . . , N − 1}.

Conversely, if (K, N, S) is positive for SET-COVER then there is a subset cover T ⊆ S of


{0, . . . , N − 1} with |T | ≤ K. We define W = {u ∈ V | Su ∈ T }. Then |W | ≤ K. Now let
ei ∈ E be an edge. As T is a cover, there is Su ∈ T such that i ∈ Su . So u is an endpoint of
ei and moreover u ∈ W. In conclusion, W is a vertex cover of G.

On the other hand, the function f does not define a correct reduction. For example,
suppose that K = 1 and G is the following graph:

u0 u1 u2
246 Solutions to Final Exams

Then the input (K, G ) is positive for VERTEX-COVER, as vertex u1 covers both edges.
But f (K, G ) = (1, 3, {{0, 1}, {1, 2}}) is not positive for SET-COVER, since there is no sin-
gle subset that covers {0, 1, 2}.

(c) If VERTEX-COVER reduces polynomially to SET-COVER and moreover we have that


VERTEX-COVER is NP-hard (given that it is NP-complete), then we can say that SET-COVER
is NP-hard: given a problem X of class NP, we can compose the reduction from X to
VERTEX-COVER with the reduction from
VERTEX-COVER to SET-COVER, and in this way obtain a reduction from X to SET-COVER.
But with only that we cannot deduce that SET-COVER is NP-complete, as we need to
justify that it belongs to NP. So let us see that indeed SET-COVER belongs to NP. In this
case the witnesses are the size k and the k indices of the subsets that form the set cover.
Clearly the witnesses have size not greater than the size of the input. And verifying that
a choice of k subsets gives a set cover only requires to check that every number from 0
to N − 1 belongs to at least one of the subsets. This can be done in polynomial time in
the size of the input as the subsets of the input form a set cover of {0, . . . , N − 1} and
therefore the size of the input is ≥ N.

You might also like