Presentation is loading. Please wait.

Presentation is loading. Please wait.

Algorithm Design and Analysis (ADA)

Similar presentations


Presentation on theme: "Algorithm Design and Analysis (ADA)"— Presentation transcript:

1 Algorithm Design and Analysis (ADA)
, Semester 7. Dynamic Programming Objective introduce DP; look at several examples compare DP to Greedy

2 Overview 1. DP Features 2. The fibonacci series 3. Binomial coefs
knapsack 5. Longest Common Subsequence 6. Compare DP to Greedy using fractional knapsack

3 1. DP Features An optimal (best) solution to the problem is a composition of optimal (best) subproblem solutions makes the code recursive (perhaps) The same subproblems appear many times while solving the problem use tabling / memoziation to 'remember' answers perhaps calculate subproblems first; called bottom-up evaluation The current best solution choice may change solutions choices made earlier.

4 2. Fibonacci Series Series defined by Recursive algorithm:
fibn = fibn-1 + fibn-2 Recursive algorithm: Running Time? O(2n) 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, … see FibMemo.java public static int fib(int n) { if (n < 2) return n; else return fib(n-1) + fib(n-2); }

5 Fibonacci can be a DP problem:
the solution (fib(n)) is a combination of sub-solutions fib(n-1) and fib(n-2)) There are many repeated subproblems 2n subproblems, but only n are different

6 Memoization + top-down fib()
fibs[] private static long fibs = new long[MAX+1]; // in main() fibs[0] = 0; fibs[1] = 1; public static long fib(int n) { if (n < 2) return n; else { if (fibs[n] == 0) fibs[n] = fib(n−1) + fib(n−2) return fibs[n]; } } 1 1 2 3 : : : : MAX Running time is linear = O(n) Requires extra space for the fibs[] table = O(n)

7 Speed-up 10th Fib: 55 Number of fib() calls: 19 Number of fib() calls: 1 11th Fib: 89 Number of fib() calls: 3

8 Bottom-up Fib Running time = O(n)
F(k-1) F(k-2) F(k-1) temp prev curr int fib(int n) { if (n == 0) return 0; else { // deal with 1, 1, 2,... int prev = 0; int curr = 1; int temp; for (int i=1; i < n; i++) { temp = prev + curr; prev = curr; curr = temp; } return curr; + temp prev curr F(k) F(k-1) F(k) Running time = O(n) Space requirement is 5 variables = O(1) !

9 3. Binomial Coefficients
How many ways are there to choose k things out of n? Used to calculate the coefficients of of (a+b)n

10 Use Pascal’s triangle instead:
It’s difficult to calculate the value of binomial coefficients using that equation: arithmetic overflow will happen for n > 12! Use Pascal’s triangle instead: n == 0 1 1 1 n == 1 : a table of subproblems that are used repeatedly. A DP problem start counting k = 0 from left

11 Binomial Coefficients
see Binomial.java private static final int MAX = 100; // return n choose m static long binCoef(int n, int m) { long[][] bc = new long[MAX][MAX}; //table of binomial coefs for(int i = 0; i <= n; i++) bc[i][0] = 1; // init upper edges for(int j = 0; j <= n; j++) bc[j][j] = 1; for(int i = 1; i <= n; i++) // fill inside triangle for(int j = 1; j < i; j++) bc[i][j] = bc[i-1][j-1] + bc[i-1][j]; return bc[n][m]; }

12 4. 0-1 Knapsack Problem 11 1 item 0 2 6 item 1 5 18 item 2 6 22 item 3
7 28 item 4 indivisible; use or not use a weight maximize cost, but total weight ≤ 11 11 Crucial idea: total weight must be one of 12 values: 0-11

13 1 item 0 2 6 item 1 5 18 item 2 Maximize cost with at most 3 items: 1 2 3 4 5 6 7 8 9 10 11 w = c = 18 19 24 25 6 22 item 3 Try to add item 3: 1 2 3 4 5 6 7 8 9 10 11 w = c = 18 22 24 28 29 40

14 Mathematically Items 0, 1, ... n have weights w0, w1, ...wn and costs c0, c1, ...cn. All values are positive integers. W is the maximum capcity of the knapsack. Define m[i,w] to be the maximum total cost with weight ≤ w using items 0 to i.

15 Define m[i,w] recursively
the maximum total cost with weight ≤ w using items 0 to i m[0,w] = c0 if w0 ≤ w m[i,w] = m[i-1,w], if wi > w  the i item weighs more than the current weight limit m[i,w] = max( m[i-1,w], m[i-1, w-wi]+ci ), if wi ≤ w The solution is m[n,W]. To do this efficiently we must use a table to store previous computations. don't use wi use wi

16 Why use Dynamic Prog.? The current selection may change an earlier selection: 1 item 0 2 6 item 1 5 18 item 2 5 18 item 2 6 22 item 3 c == 25; w == 8 c == 40; w == 11 earlier selection current selection

17 Code NOT EXAMINABLE see Knapsack0l.java m[][] has become totCosts[][]
public static void main(String[] args) { int W = 11; // knapsack capacity System.out.println("Knapsack capacity: " + W); // costs and weights for items int[] ci = { 1, 6, 18, 22, 28}; int[] wi = { 1, 2, 5, 6, 7}; int numItems = ci.length; for (int i=0; i < numItems; i++) System.out.println("Item " + i + ": weight = " + wi[i] + ", cost = " + ci[i]); System.out.println(); // totCosts[i, w] stores the maximum total cost // of some items in {0,1,...,i} of combined weight <= w int[][] totCosts = new int[numItems][W + 1]; // used[i, weight] is true when item i is part of the solution for weight boolean[][] used = new boolean[numItems][W + 1]; // all false by default : m[][] has become totCosts[][]

18 // compute maximum cost for first item for (int w = 0; w <= W; w++) { if (wi[0] <= w) { totCosts[0][w] = ci[0]; // first line of maths (slide 15) used[0][w] = true; // means that item 0 can be used when weight is w } else totCosts[0][w] = 0; // compute maximum cost for rest of items for (int i = 1; i < numItems; i++) { for (int w = 0; w <= W; w++) { // w == current weight limit if (wi[i] <= w) { // item within current weight limit int costWith_i = ci[i] + totCosts[i-1][w-wi[i]]; if (costWith_i > totCosts[i-1][w]) { // higher cost is better; third line of maths totCosts[i][w] = costWith_i; used[i][w] = true; else // leave cost unchanged totCosts[i][w] = totCosts[i-1][w]; else // item exceeds current weight limit; don't use totCosts[i][w] = totCosts[i-1][w]; // second line of maths printTables(totCosts, used); itemsUsed(used, ci, wi); } // end of main()

19 private static void itemsUsed(boolean[][] used, int[] ci, int[] wi) { System.out.println("Items used:"); int wCapacity = used[0].length-1; // start at maximum weight (W) int usedWeight = 0; int usedCost = 0; // check if i is part of the set of items weighing wCapacity, // if yes, print i info, and reduce wCapacity by item i's weight // and find the next item for this new capacity for (int i = used.length-1; i >= 0; i--) { if (used[i][wCapacity]) { System.out.println("Item " + i + ": weight = " + wi[i] + ", cost = " + ci[i]); usedWeight += wi[i]; usedCost += ci[i]; wCapacity = wCapacity - wi[i]; } System.out.println("Total weight: " + usedWeight + "; Total cost: " + usedCost); } // end of itemsUsed()

20 Execution

21 Using used[][] Items used: Weight 0 1 2 3 4 5 6 7 8 9 10 11
Item 0: X X X X X X X X X X X Item 1: X X X X X X X X X X Item 2: X X X X X X X Item 3: X X X X X Item 4: X X X X W = 11 Item 3 used; weight == 6 W = 11 – 6 = 5 Item 2 used; weight == 5 W = 5 – 5 = 0 No item used; stop

22 5. Longest Common Subsequence (LCS)
Given two sequences x[1 . . m] and y[1 . . n], find a longest subsequence common to them both. m values x: A B C B D A B BCBA = LCS(x, y) y: B D C A B A or BDAB, BCAB n values

23 Brute-force LCS Algorithm
Check every subsequence of x[1 . . m] to see if it is also a subsequence of y[1 . . n]. Analysis • Checking time for each subsequence is O(n). • 2m subsequences of x[] (can use or not use each element in x). Worst-case running time = O(n*2m), exponential time.

24 Towards a Better LCS Algorithm
Simplify the problem: Find the length of a LCS 2. We'll extend the algorithm later to find the LCS.

25 Prefixes If X = < A, B, C, B, D, A, B > then
A prefix is x[1 .. 4] == < A, B, C, B > we abbreviate this as x4 Also x0 is the empty sequence

26 Creating a Table of Lengths
c[] is a table (2D array) for storing LCS lengths: c[i, j] = | LCS(x[1. . i], y[1. . j]) | | s | is the length of a sequence s Since x is of length m, and y is of length n, then c[m, n] = | LCS(x, y) |

27 Calculating LCS Lengths
Since X0 and Y0 are empty strings, their LCS is always empty (i.e. c[0, 0] == 0) The LCS of an empty string and any other string is empty, so for every i and j: c[0, j] == c[i, 0] == 0

28 Initial c[] 0 1 2 3 4 5 1 2 3 4 prefixes of Y n = prefixes of X m =
prefixes of X 1 2 3 m = 4 this will eventually contain the answer | LCS(x,y)| c[m, n] == c[3,2]

29 Recursive Definition of c[]
The first line of this definition fills the top row and first column of c[] with 0's.

30 When we calculate c[i, j], there are two cases:
First case: x[i] == y[j]: one more symbol in strings X and Y matches, so the length of LCS Xi and Yj equals the length of LCS of smaller strings Xi-1 and Yi-1 , plus 1

31 Second case: x[i] != y[j]
As symbols don’t match, our solution is not improved, and the length of LCS(Xi , Yj) is the same as the biggest from before (i.e. max of LCS(Xi, Yj-1) and LCS(Xi-1,Yj)

32 Repeated Subproblems? Does the LCS() algorithm have many repeating (overlapping) subproblems? Consider the worst case execution x[i] ≠ y[ j], in which case the algorithm evaluates two subproblems, each with only one parameter decremented

33 Recursion Tree (in worst cases)
Height = m + n. The total work is exponential, but we’re repeating lots of subproblems.

34 Memoization LCS(x, y, i, j)
if c[i, j] is empty then // calculate if not already in c[i, j] if i == 0 or j == 0 then c[i, j] ← 0 else if x[i] == y[ j] then c[i, j] ← LCS(x, y, i–1, j–1) + 1 else c[i, j] ← max( LCS(x, y, i–1, j), LCS(x, y, i, j–1) ) return c[i, j] Time = O(m*n) == constant work per table entry Space = O(m*n)

35 Bottom-up Execution This algorithm works top-down
start with large subsequences, and calculate the smaller subsequences Let's switch to bottom-up execution calculate the small subsequences first, then move to larger ones

36 LCS Length Bottom-up the same recursive definition of c[] as before
LCS-Length(X, Y) 1. m = length(X) // get the # of symbols in X 2. n = length(Y) // get the # of symbols in Y 3. for i = 1 to m c[i,0] = 0 // special case: Y0 4. for j = 1 to n c[0,j] = 0 // special case: X0 5. for i = 1 to m // for all Xi 6. for j = 1 to n // for all Yj 7. if ( Xi == Yj ) 8. c[i,j] = c[i-1,j-1] else c[i,j] = max( c[i-1,j], c[i,j-1] ) 10. return c the same recursive definition of c[] as before

37 Bottom-up Examples LCS(X, Y) = BCB X = A B C B Y = B D C A B
We’ll see how a bottom-up LCS works on: X = ABCB Y = BDCAB LCS(X, Y) = BCB X = A B C B Y = B D C A B LCS-length(X, Y) = 3

38 LCS Example 1 ABCB BDCAB X = ABCB; m = |X| = 4 Y = BDCAB; n = |Y| = 5
j i Yj B D C A B Xi "" A 1 "A" B 2 "AB" 3 C "ABC" 4 B "ABCD" "" "B" "BD" "BDC" "BDCA" "BDCAB" X = ABCB; m = |X| = 4 Y = BDCAB; n = |Y| = 5 Allocate array c[5,4]

39 ABCB BDCAB for i = 1 to m c[i,0] = 0 for j = 1 to n c[0,j] = 0
Yj B D C A B Xi A 1 B 2 3 C 4 B for i = 1 to m c[i,0] = 0 for j = 1 to n c[0,j] = 0

40 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 B 2 3 C 4 B
A 1 B 2 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

41 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 B 2 3 C 4 B
A 1 B 2 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

42 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 B 2 3 C 4 B
A 1 1 B 2 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

43 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 3 C 4 B
A 1 1 1 B 2 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

44 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 3 C 4 B
A 1 1 1 B 2 1 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

45 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 3 C 4 B
A 1 1 1 B 2 1 1 1 1 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

46 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 4
A 1 1 1 B 2 1 1 1 1 2 3 C 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

47 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 1
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

48 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 1
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

49 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 1
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 4 B if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

50 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 1
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 4 B 1 if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

51 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 1
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 4 B 1 1 2 2 if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

52 3 ABCB BDCAB j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 3 4 B 1 1 2 2 if ( Xi == Yj ) c[i,j] = c[i-1,j-1] + 1 else c[i,j] = max( c[i-1,j], c[i,j-1] )

53 Running Time The bottom-up LCS algorithm calculates the values of each entry of the array c[m, n] So what is the running time? O(m*n) Since each c[i, j] is calculated in constant time, and there are m*n elements in the array

54 Code NOT EXAMINABLE see LCS.java c[][] has become lengths[][]
private static void lcs(String x, String y) { int[][] lengths = new int[x.length()+1][y.length()+1]; // filled with 0's by default for (int i = 1; i <= x.length(); i++) { for (int j = 1; j <= y.length(); j++) { if (x.charAt(i-1) == y.charAt(j-1)) // Java string index starts at 0, not 1 lengths[i][j] = lengths[i-1][j-1]+1; else lengths[i][j] = Math.max(lengths[i][j-1], lengths[i-1][j]); } System.out.println("LCS length: " + lengths[x.length()][y.length()]); System.out.println("LCS: " + getSubSeq(x, y, lengths)); } // end of lcs() c[][] has become lengths[][]

55 Finding the LCS We have found the length of LCS.
We want to modify this algorithm to have it calculate LCS of X and Y Each c[i, j] depends on c[i-1, j] and c[i, j-1] or c[i-1, j-1] For each c[i, j] we can trace back how it was calculated: 2 2 For example, here c[i, j] = c[i-1, j-1] +1 = 2+1=3 2 3

56 Whenever c[i,j] = c[i-1, j-1]+1, record x[i] as part of the LCS
Remember that: So we can start from c[m,n] (bottom right of c[]) and move left or up backwards if adj. squares are equal Whenever c[i,j] = c[i-1, j-1]+1, record x[i] as part of the LCS When i=0 or j=0, we have reached the beginning, so can stop.

57 Finding LCS Example 1 3 j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 3 4 B 1 1 2 2

58 j i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 3 4 B 1 1 2 2

59 3 LCS: B C B j 0 1 2 3 4 5 i Yj B D C A B Xi A 1 1 1 B 2 1 1 1 1 2 3 C
A 1 1 1 B 2 1 1 1 1 2 3 C 1 1 2 2 2 3 4 B 1 1 2 2 LCS: B C B

60 LCS() Offers Choices A B C B D A B 1 1 1 B 1 1 1 1 2 D 1 1 1 1 2 2 2 2
There may be several paths through the table, which represent different answers for LCS() LCS() = BDAB All of them have the LCS-length of 4 A B C B D A B 1 1 1 B 1 1 1 1 2 D 1 1 1 1 2 2 2 2 C 1 2 2 2 2 1 3 A 1 2 2 2 2 3 2 3 3 4 B 1 2 3 3 3 1 4 4 A 2 2 3 3 4 4

61 Code NOT EXAMINABLE see LCS.java c[][] has become lengths[][]
private static String getSubSeq(String x, String y, int[][] lengths) { StringBuffer sb = new StringBuffer(); int i = x.length(); // start at bottom right int j = y.length(); while ((i != 0) && (j != 0)) { if (x.charAt(i-1) == y.charAt(j-1)) { // Java string index starts at 0, not 1 sb.append(x.charAt(i-1)); i--; j--; } else if (lengths[i][j-1] >= lengths[i][j]) j--; else i--; return sb.reverse().toString(); } // end of getSubSeq() c[][] has become lengths[][]

62 Execution

63 6. DP Compared to Greedy DP features Again Optimal sub-structure:
the best solution to the problem uses the best solutions to sub-problems use recursive code Overlapping (repeating) problems: the same subproblems appear several times while solving the problem use tabling / memoziation to 'remember' answer The current best solution choice may change solutions choices made earlier.

64 Greedy Features Optimal sub-structure: (same as DP)
the best solution to the problem uses the best solutions to sub-problems use recursive code The current best solution choice is made using only current ('local') information greedy algorithms never change choices made earlier in the calculation makes "greedy" code easier to implement than DP

65 Examples (we'll look at them later):
Minimum Spanning Tree Algorithms – Kruskal’s and Prim’s Dijkstra’s Algorithm

66 Fractional Knapsack Problem
Maximize the value of a knapsack that can hold at most W units worth of goods from a list of items I1, I2, ... In. Each item i has two attributes: Cost/unit == vi Weight == wi

67 Fractional Knapsack Algorithm
Sort the items into a list by cost/unit. Take as much of the most expensive item as possible, then move down the list. You may end up taking a fractional portion of the last item.

68 Fractional Knapsack Problem
1 item 0 2 6 item 1 5 18 item 2 6 22 item 3 7 28 item 4 uses a greedy algorithm divisible; can use parts of a weight maximize cost, but total weight ≤ 11 11 Crucial idea: order by cost per unit weight

69 1 item 0 2 6 item 1 5 18 item 2 6 22 item 3 7 28 item 4 reorder by decreeasing cost/unit weight: 7 28 item 4 6 22 item 3 5 18 item 2 2 6 item 1 1 item 0 cost/unit weight: 4 3.666 3.6 3 1

70 Maximize cost by adding weights (or parts) in decreasing
cost/ unit weight: 7 + 4 Max weight == 11 : 7 28 item 4 6 22 item 3 Max cost == 7 * 4 + 4 * 3.666 = =

71 Input Data Format 5 11 1 1 6 2 18 5 22 6 see fkData.txt 28 7
No. of items, knapsack W Lines of item info; on each line: ci, wi for an item e.g. 5 11 1 1 6 2 18 5 22 6 28 7 see fkData.txt This is the example from the previous slides.

72 Code NOT EXAMINABLE public static void main(String[] args) throws Exception { if (args.length != 1) { System.out.println("Usage: java FracKnapsack <data-file>"); return; } Scanner sc = new Scanner(new File(args[0])); int numItems = sc.nextInt(); int maxW = sc.nextInt(); LinkedList<KItem> items = new LinkedList<KItem>(); for (int i = 0; i < numItems; i++) items.add( new KItem(sc.nextInt(), sc.nextInt()) ); Collections.sort(items); :

73 int currWeight = 0; double currCost = 0; while ((currWeight < maxW) && (!items.isEmpty())) { int remWeight = maxW - currWeight; KItem item = items.poll(); if (item.weight <= remWeight) { // add all of the item currWeight += item.weight; currCost += item.cost; } else { // item.weight > remWeight // add a fraction of the item currCost += remWeight * item.costWeightRatio; currWeight += remWeight; System.out.printf("%.3f", currCost); } // end of main()

74 public class KItem implements Comparable<KItem> { public int cost, weight; public double costWeightRatio; public KItem(int cost, int weight) this.cost = cost; this.weight = weight; costWeightRatio = ((double) cost) / weight; } public int compareTo(KItem i) double diff = costWeightRatio - i.costWeightRatio; if (diff > 0) return -1; else if (diff == 0) return 0; else return 1; } // end of compareTo() public String toString() { return "(cost: " + cost + ", weight: " + weight + ")"; } } // end of KItem class

75 Why is it Greedy? The current selection does not affect the earlier selection: 7 28 item 4 7 28 item 4 6 22 item 3 7 * 4 7 * 4 + 4 * 3.666 c = 28; w == 7 c == ; w == 11 earlier selection current selection


Download ppt "Algorithm Design and Analysis (ADA)"

Similar presentations


Ads by Google