<<

1 1.8 Counting Boolean Parenthizations Given a boolean expression consisting of n Trues and Falses connected 1.1 Knapsack Problem by either and, or, or xor, find the number of ways to parenthesize the expression such that it evaluates to True. Given a of n items with integer sizes s and values v , and a knapsack i i Subproblems T (i, j): Number of ways to parenthesize booleans i of capacity C, find a set of items whose total size is less than C, but whose through j such that the subexpression evaluates to True. value is maximized. Items may be used more than once. F (i, j): similar, but number of ways to subexpression False Subproblem: M(j): the maximum value that can be packed into a size S(i, j)=T (i, j)+F (i, j) j knapsack Recurrence Recurrence: M(j) = max M(j 1), max1 i n M(j si)+vi { − ≤ ≤ − } Running time: O(nC) time: C subproblems, each taking O(n) time. T (i, k)T (k +1,j) 8operator after k is and 1.2 0/1 Knapsack Problem > >S(i, k) S(k +1,j) F (i, k)F (k +1,j) T (i, j)= > − The knapsacp problem, but it is forbidden to use more than one of each >operator after k is or i k j 1 <> item. ≤ X≤ − T (i, k)F (k +1,j)+F (i, k)T (k +1,j) Subproblem: M(i, j): optimal value for filling exactly capacity j knap- > >operator after k is xor sack with a subset of items 1, . . . , i. > > Recurrence: M(i, j) = max M(i j, j),M(i 1,j s )+v Running time: O(n3)::> n2 subproblems, each taking O(n) time { − − − i i} These represent not using the ith item, and using the ith item, respec- tively. Solution: max M(n, j) 1.9 Subset Sum j { } Running time: O(nC) time: nC subproblems that take O(1) time Given a sequence of n numbers x1, . . . , xn, select the subset with the maxi- mum total sum, subject to the constraint that you can’t select two adjacent elements 1.3 Longest in a DAG Subproblems S(i): maximum sum of the first i numbers Recurrence S(i) = max(S(i 2) + x ,S(i)) Given a DAG G =(V,E), find the longest s t path. − i → Running time: O(n) time: n subproblems, each taking O(1) time. Subproblem: d[u]: length of longest u t path → Recurrence: d[u] = max(u,v) E (w(u, v)+d[v]) Running Time: Θ(V + E): Solve∈ with a DFS on G. 1.10 Reducable Problems 1.10.1 Box Stacking 1.4 Max Value Contiguous Subsequence Given a stack of 3-D boxes with height hi, width wi, and depth di, create Given a sequence of n real numbers A1,...,An, determine a contiguous the tallest stack of boxes possible, where box j can only be stacked on box j i if wi >wj and di >dj . subsequence Ai,...,Aj for which the l=i Al is maximized. Subproblem: M(j): max window ending at j Reduction: Make a box for each possible rotation of the original set P of boxes. Assume w d . Sort boxes in order of decreasing base . Recurrence: M(j) = max M(j 1) + Aj ,Aj i i { − } Problem is now Longest≤ Increasing Subsequence Solution: maxj M(j) Running time: O(n) time: n subproblems each take O(1) time 1.10.2 Building Bridges 1.5 Making Change Consider a map with a horizontal river. There are n cities on the southern bank with increasing x-coordinates A1,...,An, and correponding cities on Given coin denominations of values 1 = v1 < . . . < vn, and an amount of the northern bank with x-coordinates (that are not necessarily increasing) money C, make C cents in change with as few coins as possible. B1,...,Bn. Connect as many Ai,Bi pairs as possible without bridges Subproblem: M(j): minimum coins needed to make change for j cents crossing. Recurrence: M(j) = min M(j v ) +1 Reduction: Define a list with element i as the index of city i on the i{ − i } Running time: O(nC) time: C subproblems that take O(n) time northern bank. Find the Longest Increasing Subsequence of that list.

1.6 Longest Increasing Subsequence 1.10.3 Picking Up Pennies Given a DAG G =(V,E) where some edges have pennies, find a path s t Given a sequence of n real numbers A1,...,An, find the longest subse- with the most pennies. → quence (not necessarily contiguous) where values in the subsequence are Reduction: Define w(u, v) = number of pennies on edge. Then Longest strictly increasing. Path. Subproblem: L(j): longest strictly increasing subsequence ending at position j. Recurrence: L(j) = max L(i) +1 i 1 T (i, j 1) + Ci c T (i, j) = min 8 − n , 0 < c < 1 n > T (i 1,j 1),A[i] == B[j] n log n = log n! n2 <> − − 3 c (T (i 1,j 1), else n n , c > 0 − − n n > 2 3 Running time O(nm):> time: nm subproblems that each take O(1) time cn, c > 1 n!

1 3 Heaps MERGE-SORT(A, p, r) 1 if p < r Invariant (for max-heap): if B is a child of A then A > B. 2 then q <- (floor((p + r)/2) 3 MERGE-SORT(A, p, q) heapify Θ(log n) • 4 MERGE-SORT(A, q + 1, r) Assumes that LEFT(i) and RIGHT(i) are heaps, but that A[i] may 5 MERGE(A, p, q, r) violate the invariant function merge(left,right) def heapify(A, i): var list result l = left(i) while length(left) > 0 and length(right) > 0 r = right(i) if first(left) <= first(right) if l <= len(A) and A[l] > A[i]: append first(left) to result largest = l left = rest(left) else: else largest = i append first(right) to result right = rest(right) if r <= len(A) and A[r] > A[largest}: end while largest = r while length(left) > 0 append left to result if largest != i: while length(right) > 0 A[i], A[largest] = A[largest], A[i] append right to result heapify(A, largest) return result

extract-max Θ(log n) Heap Sort • • in a nutshell: 1. Build . 2. Grab root. 3. Max-heapify. def extract_max(A): 4. Go to 2. Not stable, but the n lg n worst case is nice. Usually max = A[0] slower than quicksort. A[0] = A.pop(-1) HEAPSORT(A) heapify(A, 0) 1 BUILD-MAX-HEAP(A) return max 2 for i <- length[A] downto 2 3 do exchange A[1] <-> A[i] increase-key Θ(log n) 4 heap-size[A] <- heap-size[A] - 1 • 5 MAX-HEAPIFY(A, 1) def increase_key(A, i, key): Counting Sort A[i] = key • while i > 0 and A[parent(i)] < A[i]: COUNTING-SORT(A, B, k) A[i], A[parent(i)] = A[parent(i)], A[i] 1 for i <- 0 to k i = parent(i) 2 do C[i] <- 0 3 for j <- 1 to length[A] insert Add to the end of the heap, then increase-key to the 4 do C[A[j]] <- C[A[j]] + 1 • actual value −∞ 5 C[i] now contains the number of elements equal \ to i. 6 for i <- 1 to k 7 do C[i] <- C[i] + C[i - 1] 4 Sorting 8 C[i] now contains the number of elements less \ than or equal to i. Algorithm Best Worst Stable In-place 9 for j <- length[A] downto 1 Insertion Sort nn2 YY 10 do B[C[A[j]]] <- A[j] Merge Sort n lg nnlg n YN 11 C[A[j]] <- C[A[j]] - 1 Heap Sort nnlg n NY Quicksort Counting Sort nn YN • Quicksort n lg nn2 some versions N QUICKSORT(A, p, r) 1 if p < r Insertion Sort • 2 then q <- PARTITION(A, p, r) Very good on sorted sets; online; good for small sets. Atrocious for 3 QUICKSORT(A, p, q - 1) large sets. 4 QUICKSORT(A, q + 1, r) INSERTION-SORT(A) PARTITION(A, p, r) 1 for j <- 2 to length[A] 1 x <- A[r] 2 do key <- A[j] 2 i <- p - 1 3 Insert A[j] into the sorted sequence A[1... j - 1]. 3 for j <- p to r - 1 4 i <- j - 1 4 do if A[j] <= x 5 while i > 0 and A[i] > key 5 then i <- i + 1 6 do A[i + 1] <- A[i] 6 exchange A[i] <-> A[j] 7 i <- i - 1 7 exchange A[i + 1] <-> A[r] 8 A[i + 1] <- key 8 return i + 1 Merge Sort • Radix sort Wikipedia: ”Although heapsort has the same time bounds as merge • sort, it requires only Θ(1) auxiliary space instead of merge sort’s Θ(n), RADIX-SORT(A, d) and is often faster in practical implementations. Quicksort, however, 1 for i <- 1 to d is considered by many to be the fastest general-purpose sort algorithm. 2 do use a stable sort to sort array A on digit i On the plus side, merge sort is a stable sort, parallelizes better, and is more efficient at handling slow-to-access sequential media. Merge sort Given nd-digit numbers in which each digit can take on up to k possi- is often the best choice for sorting a : in this situation it is ble values, RADIX-SORT correctly sorts these numbers in Θ(d(n+k)) relatively easy to implement a merge sort in such a way that it requires time. Stable; not in-place. only Θ(1) extra space, and the slow random-access performance of a Bucket Sort linked list makes some other (such as quicksort) perform • Assumes that the input is generated by a random process that dis- poorly, and others (such as heapsort) completely impossible.” tributes elements uniformly over [0,1)

2 BUCKET-SORT(A) Bellman-Ford 1 n <- length[A] • The Bellman-Ford algorithm solves the single-source shortest-paths 2 for i <- 1 to n problem in the general case in which edge weights may be negative. 3 do insert A[i] into list B[floor(n A[i])] Given a weighted, G = (V, E) with source s and weight 4 for i <- 0 to n - 1 function w : E R, the Bellman-Ford algorithm returns a boolean 5 do sort list B[i] with insertion sort value indicating→ whether or not there is a negative-weight that 6 concatenate the lists B[0], B[1],..., B[n - 1] together in order is reachable from the source. If there is such a cycle, the algorithm indicates that no solution exists. If there is no such cycle, the al- gorithm produces the shortest paths and their weights. If the graph 5 Search does contain a cycle of negative weights, Bellman-Ford can only detect this; Bellman-Ford cannot find the shortest path that does not repeat d[u] is time u is discovered (added to queue) any in such a graph. This problem is at least as hard as the • f[u] is time that u is finished (removed from queue) NP-complete . The algorithm uses relaxation, progressively decreasing an estimate Tree edges are edges in the depth-first forest Gp. Edge (u, v) is a tree • edge if v was first discovered by exploring edge (u, v). Edge (u,v) is a d[v] on the weight of a shortest path from the source s to each tree or forward edge iff d[u] d[u] + w(u, v) same depth-first tree, as long as one vertex is not an ancestor of the 7 then return FALSE other, or they can go between vertices in different depth-first trees. 8 return TRUE Edge (u,v) is a cross edge if and only if d[v]

3 Figure 24.1: Negative edge weights in a directed graph. Shown within each vertex is its shortest- Figure 24.3: Relaxation of an edge (u, v) with weight w(u, v) = 2. The shortest-path estimate path weight from source s. Because vertices e and f form a negative-weight cycle reachable from of each vertex is shown within the vertex. (a) Because d[v] > d[u] + w(u, v) prior to relaxation, s, they have shortest-path weights of −∞. Because vertex g is reachable from a vertex whose the value of d[v] decreases. (b) Here, d[v] ≤ d[u] + w(u, v) before the relaxation step, and so shortest-path weight is −∞, it, too, has a shortest-path weight of −∞. Vertices such as h, i, and d[v] is unchanged by relaxation. j are not reachable from s, and so their shortest-path weights are −∞, even though they lie on a negative-weight cycle.

Figure 24.4: The execution of the Bellman-Ford algorithm. The source is vertex s. The d values Figure 24.6: The execution of Dijkstra’s algorithm. The source s is the leftmost vertex. The are shown within the vertices, and shaded edges indicate predecessor values: if edge (u, v) is shortest-path estimates are shown within the vertices, and shaded edges indicate predecessor shaded, then π[v] = u. In this particular example, each pass relaxes the edges in the order (t, values. Black vertices are in the set S, and white vertices are in the min-priority queue Q = V x), (t, y), (t, z), (x, t), (y, x), (y, z), (z, x), (z, s), (s, t), (s, y). (a) The situation just before the - S. (a) The situation just before the first iteration of the while loop of lines 48. The shaded first pass over the edges. (b)(e) The situation after each successive pass over the edges. The d vertex has the minimum d value and is chosen as vertex u in line 5. (b)-(f) The situation after and π values in part (e) are the final values. The Bellman-Ford algorithm returns TRUE in this each successive iteration of the while loop. The shaded vertex in each part is chosen as vertex u example. in line 5 of the next iteration. The d and values shown in part (f) are the final values.

Figure 24.5: The execution of the algorithm for shortest paths in a . The Figure 8.4: The operation of BUCKET-SORT. (a) The input array A[1 10]. (b) The array B[0 vertices are topologically sorted from left to right. The source vertex is s. The d values are 9] of sorted lists (buckets) after line 5 of the algorithm. Bucket i holds values in the half-open shown within the vertices, and shaded edges indicate the values. (a) The situation before the interval [i/10, (i + 1)/10). The sorted output consists of a concatenation in order of the lists first iteration of the for loop of lines 35. (b)(g) The situation after each iteration of the for loop B[0], B[1], . . ., B[9]. of lines 35. The newly blackened vertex in each iteration was used as u in that iteration. The values shown in part (g) are the final values.