20-CS-781

Advanced Algorithms 1

Winter 2009

Meeting Time: MWF 11:00am-11:50 pm Baldwin


Instructor: Fred Annexstein

Office: 889 Rhodes (

Phone: 556-1807

Email: fred.annexstein (at) uc.edu

Web: http://www.cs.uc.edu/~annexste


Course Information

 

Class Meeting: M W F    1:00 PM   1:50 PM   BALDWIN 661

 
 
Course syllabus
 

 


Important Information and News

 

 
HOMEWORK
 
Assignments
Item    Homework #4: Due Friday March 13
1. Show that 2-coloring is in P
 
2. Show that 2-SAT is in P. Hint: For each clause (x v y) in the instance, we know that if the instance is satisfiable that not x implies y, and not y implies x. Build a graph based on these implications.
 
3.  Low-Diameter Clustering problem: given n objects p1 , p2 , . . . , pn with pairwise distances between them, and a bound B, we ask can the objects be partitioned into k sets, so that no two points in the same set are at distance greater than B from one another? Prove that this problem is NP-complete (Hint: try a reduction from 3-coloring)
 
4. (26.16) Show that 0/1 Knapsack is NP-complete. (Hint: try a reduction from Partition)
 
5.(26.17) Show that Bin-Packing is NP-complete (Hint: try a reduction from SumofSubsets)
 
            
Item    Homework #3: Due Monday March 2 in class
Advanced Algorithms 1 (781) --- Winter 2009
Assignment 3
 
Due Monday, March 2 at the beginning of the class
 
0.  Consider the problem of finding an independent set of vertices (no pair share an edge) on a path whose weight is as large as possible. a) Show an example path that shows the greedy algorithm sometimes fails. b) Show an example path that shows that choosing the odd or even vertices on the path sometimes fails. c) Give a dynamic programming solution that always finds the optimal.  
 
1. Write a Python program to solve the "optimal parenthesization" problem. Use your code to solve page 285, Exercise 9.7
 
2. Page 286, Exercise 9.10
 
3. Page 286, Exercise 9.15
 
4. Page 287, Exercise 9.17
 
5. Page 287, Exercise 9.20
 
 
            
Item    Homework #2 Due Friday Feb 6 5:00PM
Do the following exercies:
1. p. 110 3.35
2. p. 111 3.49
3. p. 712 22.2
4. P. 712 22.8
5. p. 262 8.13
6. p. 234 7.14
7. p. 234 7.15
8. Formally show that if T is an optimal prefix tree with probabilities {p_1, ..., p_k},
   then p_i < p_j implies that depth(message_i) >= depth(message_j)
            
Item    Homework #1 Due in Digital Dropbox Friday Jan 16 5:00PM
CS781- Winter 2009
Homework #1 Due in Digital Dropbox Friday Jan 16 5:00PM
 
1. Using the definition, show that for any constant k,  (n+k)^4 is O(n^4).
2. Using the definition, show that if p(n) is a polynomial in n, then log(p(n)) is O(log n).
3. Using the definition, show that for any pair of constants 0< e <1, and k>1 that n^e is Omega(log^k n)
4. Suppose you implement a vector (extendable array) in which each push_back (add) operation takes a) constant time if sufficient space is allocated or b) time proportional to the current size of the vector, if the structure is full. In class we showed that if each extention doubled the size of the vector than the cost of n push_back operations is O(n) time.
    a) suppose each extension increased the size of the vector by a constant size k. What is the complexity of n push_back operations? Prove your answer.
    b) suppose each extension increased the size of the vector by a number equal to ceiling of sqrt of size. What is the complexity of n push_back operations? Prove your answer is correct.
 
5. I am thinking of two positive integers m < n. I tell you n, and your task is to determine m. For each guess you give, I will only tell you whether m is "correct", "higher" or "lower". However, if I say "lower" two times, you have failed the task.  How many guesses will you need to determine m without fail? Show that your answer is optimal up to constant factors.
 
6. Suppose you are given a 0/1 nxn matrix A, in which all the rows are sorted. Give an O(n) algorithm that determines the row(s) of A with the most 1s. Show that your algorithm is O(n) and not O(n^2).
 
7. Convert the following O(n^2) Python program to compute running statistics to a linear time algorithm
 
# Quadratic time for running averages and variances
def main (x):
    run_avg=[]
    run_var=[]
    partial_sum=0
    for i in range(len(x)):
        partial_sum += x[i]
        run_avg.append(partial_sum/(i + 1.0))
        partial_sumsquares=0
        for j in range(i+1):
            partial_sumsquares += (x[j]-run_avg[i])**2
        run_var.append(partial_sumsquares/(i+1.0))
    for i in range(len(x)):
        print "%5.2f , %5.2f, %5.2f" % (x[i], run_avg[i], run_var[i])
 
main([1,1,1,0,0,0,1,1])
>>> 
 1.00 ,  1.00,  0.00
 1.00 ,  1.00,  0.00
 1.00 ,  1.00,  0.00
 0.00 ,  0.75,  0.19
 0.00 ,  0.60,  0.24
 0.00 ,  0.50,  0.25
 1.00 ,  0.57,  0.24
 1.00 ,  0.62,  0.23
 
LECTURE NOTES
 
Lecture on Polynomial Multiplication - Jan 16
FFT.pdf (632.158 Kb)
 
Midterm Practice Exam
Midterm-781-2009.doc (38.5 Kb)
 
3-coloring and NP-completeness course notes
3-coloring.pdf (439.243 Kb)
planarGraphColoring.pdf (376.529 Kb) 
 
 
Approximating NPC Problems
781-NPC.htm (19.791 Kb)
781-NPC2.htm (15.244 Kb)
781-NPC3.htm (20.403 Kb) 
 
 
Notes March 11- K-Center Problems and Solutions
CS781-March 11.pdf
 
 
 
Final Practice Exam and Topic Sheet
FInalStudy-781-2009.doc (36.5 Kb)
 
 
 
CODE SAMPLES
 
 
Python generators of combinatorial objects
#Python has very nice syntax for defining generators of combinatorial objects such as subsets, k-element subsets, permutations, etc.
#The syntax lends itself to be used in a natural way with "for" statements. Generators work off the "yield" construct which suspends the
#state of the function, and is continued from precisely that point when the generator.next() is called from behind the scenes of a for statement.
#Here are some example generators
 
#The classic Fibonacci sequence as a generator
 
def fib():
            a, b = 0, 1
            while 1:
                yield b
                a, b = b, a+b
 
#for i in fib():
#    print i
 
#The generator of all subsets
 
def all_subsets(str):
    if len(str) < 1:
        yield str
    else:
        for subset in all_subsets(str[1:]):
            yield str[0:1] + subset
            yield subset
 
#for s in all_subsets(['a','b','c','d']):
#    print s
#for s in all_subsets("abcd"):
#    print s
   
 
#A tour de force: a generator of all permutations
def all_permutations(str):
    if len(str) <=1:
        yield str
    else:
        for perm in all_permutations(str[1:]):
            for i in range(len(perm)+1):
                yield perm[:i] + str[0:1] + perm[i:]
 
#for p in all_permutations(['a','b','c','d','e']):
#    print p
 
Feb 18 Notes: RNA Dynamic Programming Example
#Predicting RNA Secondary Structure
 
def printpairs(i,j,R):
    if i>=j-4:
        return
    else:
        x = opt(i,j,R)
    if x[0]==0: #no pairs
        return
    elif x[1]==-1: # base j not paired
      printpairs(i,j-1,R)
    else:
        t=x[1]
        print "R[",t,"]=",R[t]," --- R[",j, "]=", R[j]
        printpairs(i,t-1,R)
        printpairs(t+1,j-1,R)
 
def opt(i,j,R):
#for each pair i,j this function returns the max number of base pairs
#in the interval from i to j in R as well as the pairing
#of jth base that achieves this; base j is paired with base maxt
 
    if j - i < 5:
          return [0,'x'] # no pairings possible in small interval
    else:
          maxsofar = opt(i,j-1,R)[0]
          maxt = -1
          for t in range(i,j-4):
            if WCpair(R[t],R[j]):
                val = 1+ opt(i, t-1,R)[0] + opt(t+1,j-1,R)[0]
                if maxsofar < val:
                    maxsofar=val
                    maxt=t
          return [maxsofar,maxt]
 
def WCpair(x,y):
    if (x=='A' and y=='U')  or (x=='U' and y=='A'):
        return True
    if (x=='C' and y=='G')  or (x=='G' and y=='C'):
        return True
    return False
 
def main():
    #R=raw_input("Enter RNA string")
    R="GUCGAUUGAGCGAAUGUAACAACGUCGCUACGGCGAGA"
    # has maximum 12 pairs
   
    print " The maximum number of WC-base pairings for \n", R,":"
    printpairs(0,len(R)-1,R)
 
main()
 
#Here is the memoized version
def printpairsmemo(OPT,i,j,R):
    if i>=j-4:
        return
    if OPT[i][j][1]==-1:
      printpairs(OPT,i,j-1,R)
    else:
        t=OPT[i][j][1]
        print t,j,R[t],R[j]
        printpairs(OPT,i,t-1,R)
        printpairs(OPT,t+1,j-1,R)
       
def main_memoized():
 
    R="GUCGAUUGAGCGAAUGUAACAACGUCGCUACGGCGAGA"
    OPT=[]
    for i in range(len(R)):
        zrow=[]
        for j in range(len(R)):
            zrow.append([0,-1])
        OPT.append(zrow)
   
    for diag in range(len(R)):
        for i in range(len(R)-diag):
            j= i + diag
            if j-i > 4:
                OPT[i][j][0]=OPT[i][j-1][0]
                for t in range(i,j-4):
                    if WCpair(R[t],R[j]):
                       if t > i:
                           val = 1+ OPT[i][t-1][0] + OPT[t+1][j-1][0]
                       else:
                           val = 1 + OPT[t+1][j-1][0]
                       if OPT[i][j][0] < val:
                          OPT[i][j] = [val,t]
                        
    best = OPT[0][len(R)-1]
    print " The maximum number of WC-base pairings for \n", R,":", best[0]
    print "PRINT MAX WC-BASE PAIRS"
    printpairsmemo(OPT,0,len(R)-1,R)