CS 601 Exam 2 Solution

advertisement
CS 601 Exam 2 Solution
Fall 2004
Solve any 5 of these 6 problems, or try all 6 for extra credit if you have time.
1. Suppose you must take n specified courses to earn a college degree, and each course
has a set of required prerequisite courses. Design an efficient greedy algorithm that
determines the fewest number of semesters that would be needed to take all n courses,
assuming that there is no limit to the number of courses you can take simultaneously.
S  {all n courses};
semester  0;
while (S  empty set) {
semester++;
T  {courses in S that have no prerequisites in S};
take all courses in T simultaneously;
S  S - T;
}
return semester;
2. You are given an array A that contains n numbers, and you are also given a target
value T. Design a (n lg n)-time greedy algorithm that determines whether or not
the array A contains any two elements A[i] and A[j] such that A[i]+A[j]= T.
sort array A[1...n] into ascending order using merge sort;
// after sorting, the remainder of the algorithm takes only (n lg n) time:
i  1;
j  n;
while (i < j) {
if (A[i]+A[j] < T)
i++;
else if (A[i]+A[j] > T)
j--;
else // (A[i]+A[j] == T)
return true;
}
return false;
Several people tried to solve this problem using a non-greedy algorithm. If I could
have anticipated this, then I would have re-stated the problem as follows to enforce
that only a greedy approach could meet the specified time bound:
You are given an array A that contains n numbers which are arranged in ascending
order, and you are also given a target value T. Design a (n)-time greedy algorithm
that determines whether or not the array A contains any two elements A[i] and
A[j] such that A[i]+A[j]= T.
3. A sequence of n operations is performed on a data structure. The kth operation has a
cost of k when k is an exact power of 2, and otherwise it has a cost of 1. Analyze the
amortized cost per operation using any two of these methods: (a) aggregate, (b)
accounting, (c) potential. Specify which two methods you choose.
This problem has same analysis as the dynamic table data structure, with expansion
due to overflow on insertion, but without contraction due to underflow on deletion.
a) Aggregate method: Total cost ≤ 1 ≤ k ≤ n 1 + 1 ≤ j ≤ lg n 2j ≤ n + (2lg n)/(1-1/2)
≤ n + 2n = 3n. So amortized cost ≤ 3n/ n = 3 = (1).
b) Accounting method: Charge $3 per operation. When k is not a power of 2,
use $1 to pay for the operation, and place the extra $2 in an account. The
account balance will always be at least $2 times the number of operations
since the most recent power of 2. When k is a power of 2, the most recent
power of 2 was k/2, so the balance is at least $2 * ((k-1) - (k/2)). This
amount plus the $3 charge is more than enough to pay for the operation. So
amortized cost ≤ 3 = (1).
c) Potential method: Define 0 = 1 = 0 and  k = 2 * (k – 2  lg k  ) for k ≥ 2.
Intuitively, the potential is 2 times the number of operations since the most
recent power of 2. Note that  k ≥ 0 for all k. When k is not a power of 2,
amortized cost = 1 +  k -  k-1 = 1 + 2*(k – 2  lg k  ) - 2*((k-1) – 2  lg (k-1)  )
= 2*(k – 2  lg k  ) - 2*((k-1) – 2  lg k  ) = 3. When k is a power of 2,
amortized cost = k +  k -  k-1 = k + 2*(k – 2  lg k  ) - 2*((k-1) – 2  lg (k-1)  )
= k + 2*(k – 2 lg k) - 2*((k-1) – 2 lg (k/2)) = k + 0 – 2*(k-1 - k/2) = 2. So
amortized cost ≤ 3 = (1).
4. First determine the worst-case running time of algorithm A as a  function of n. Next
determine the total running time of algorithm B as a  function of n. Justify each answer.
A(n)
B(n)
if (n mod 2 == 1) return n;
else return A(n/2);
for k  1 to n do
print A(k);
Consider algorithm A. Suppose there are j calls to A before the recursion stops.
This can only happen if n/2j  1, so we know j ≤ lg n, and hence TA(n) = (lg n).
The worst case occurs when n is a power of 2.
Consider algorithm B. For n/2 values of k (the odd values), A is only called 1
time before the recursion stops. For n/4 values of k, A is called exactly 2 times.
For 1 ≤ j ≤ lg n, there are n/2j values of k for which A is called exactly j times.
Therefore TB(n) ≤ 1 ≤ j ≤ lg n n/2j * j ≤ 1 ≤ j ≤  1 ≤ i ≤ j n/2j = 1 ≤ i ≤  i ≤ j ≤  n/2j =
1 ≤ i ≤  2n/2i = 2n = (n).
5. Trace the sequence of operations below, using a disjoint set forest with union by rank
and path compression. Assume there are initially 16 sets {1},{2},…,{16}.
Draw the data structure both immediately before and after the Find_Set operation.
for (i=1; i<=16; i+=2) Union(i+1,i); // i becomes the new root
for (i=1; i<=16; i+=4) Union(i+2,i);
for (i=1; i<=16; i+=8) Union(i+4,i);
Union(9,1);
// draw the forest data structure after all Unions
Find_Set(16);
// draw the forest data structure after Find_Set
Everybody got this one mostly correct, so it’s not necessary to draw the trees here.
6. Here is a recursive version of Find_Set with path compression as given in the
textbook. Write an equivalent algorithm that is non-recursive.
Find_Set(x)
if x  parent[x] then
parent[x]  Find_Set(parent[x]);
return parent[x];
Find_Set(x)
r  x;
while r  parent[r] do
r  parent[r];
// now r is the root node
while r  parent[x] do {
p  parent[x];
parent[x]  r;
x  p;
}
return r;
Download