chapter 8 dynamic programming. algorithm 8.1.1 computing the fibonacci numbers, version 1 this...

21
CHAPTER 8 Dynamic Programming

Post on 20-Dec-2015

227 views

Category:

Documents


2 download

TRANSCRIPT

CHAPTER 8

Dynamic Programming

Algorithm 8.1.1 Computing the Fibonacci Numbers, Version 1This dynamic-programming algorithm computes the Fibonacci number f[n]. It uses the formulas

f[1] = 1; f[2] = 1; f[n] = f[n - 1] + f[n - 2], n ≥ 3.At the conclusion of the algorithm, the array f holds the first n Fibonaccinumbers.

Input Parameters: nOutput Parameters: Nonefibonacci1(n) { // f is a local array f[1] = 1 f[2] = 1 for i = 3 to n f[i] = f[i - 1] + f[i - 2] return f[n]}

Algorithm 8.1.1 Computing the Fibonacci Numbers, Version 2This dynamic-programming algorithm computes the Fibonacci number fn . It uses the formulas f1 = 1; f2 = 1; fn = fn - 1 + fn - 2, n ≥ 3. It saves the two preceding Fibonacci numbers in the variables f_twoback and f_oneback in order to compute the next Fibonacci number.

Input Parameters: nOutput Parameters: Nonefibonacci2(n) {

if (n == 1 || n == 2)return 1

f_twoback = 1 f_oneback = 1 for i = 3 to n { f = f_twoback + f_oneback f_twoback = f_oneback f_oneback = f } return f}

Computing the Fibonacci Numbers RecursivelyThis algorithm computes the Fibonacci number fn recursively using the formulas f1 = 1; f2 = 1; fn = fn - 1 + fn - 2, n ≥ 3.

Input Parameters: nOutput Parameters: Nonefibonacci_recurs(n) { if (n == 1) return 1 if (n == 2) return 1 return fibonacci_recurs(n - 2) + fibonacci_recurs(n - 1)}

Computing the Fibonacci Numbers with MemoizationThis algorithm computes the Fibonacci number fn recursively (with memoization) using the formulas f1 = 1; f2 = 1; fn = fn - 1 + fn - 2, n ≥ 3.

Input Parameters: nOutput Parameters: Nonememoized_fibonacci(n) { for i = 1 to n results[i] = -1 // -1 means undefined return memoized_fibonacci_recurs(results,n)}

memoized_fibonacci_recurs(results,n) { if (results[n] != -1) return results[n] if (n == 1) val = 1 else if (n == 2) val = 1 else { val = memoized_fibonacci_recurs(results,n - 2) val = val + memoized_fibonacci_recurs(results,n - 1) } results[n] = val return val}

Algorithm 8.2.1 Coin Changing Using Dynamic Programming, Version 1This dynamic-programming algorithm computes the minimum number of coins to make change for a given amount. The input is an array denom that specifies the denominations of the coins, denom[1] > denom[2] > ··· > denom[n] = 1,and an amount A. The output is an array C whose value, C[i][j], is theminimum number of coins to make change for the amount j, using coins ithrough n, 1 ≤ i ≤ n, 0 ≤ j ≤ A.

Input Parameters: denoma,AOutput Parameters: Nonedynamic_coin_change1(denom,A,C) { n = denom.last for j = 0 to A C[n][j] = j for i = n - 1 downto 1 for j = 0 to A if (denom[i] > j ||

C[i + 1][j] < 1 + C[i][j - denom[i]]) C[i][j] = C[i + 1][j] else C[i][j] = 1 + C[i][j - denom[i]]}

Algorithm 8.2.2 Coin Changing Using Dynamic Programming, Version 2This dynamic-programming algorithm computes the minimum number of coins to make change for a given amount and tracks which coins are used. The input is an array denom that specifies the denominations of the coins, denom[1] > denom[2] > ··· > denom[n] = 1,and an amount A. The output consists of arrays C and used. The value, C[i][j], is the minimum number of coins to make change for the amount j, using coins I through n, 1 ≤ i ≤ n, 0 ≤ j ≤ A. The value, used[i][j], is true or false to signify whether coin i appears in the smallest set of coins computed by Algorithm 8.2.1 for the amount j using only coins i through n. The values of i and j satisfy 1 ≤ i ≤ n, 0 ≤ j ≤ A.

Input Parameters: denom,AOutput Parameters: C,useddynamic_coin_change2(denom,A,C,used) { n = denom.last for j = 0 to A { C[n][j] = j used[n][j] = true }

for i = n - 1 downto 1 for j = 0 to A if (denom[i] > j ||

C[i + 1][j] < 1 + C[i][j - denom[i]]) C[i][j] = C[i + 1][j] used[i][j] = false else C[i][j] = 1 + C[i][j - denom[i]] used[i][j] = true

}}

Algorithm 8.2.4 Computing a Minimum-Size Set of Coins for a Given AmountThis algorithm outputs a minimum-size set of coins to make change for an amount j using any of coins i through n with denominations specified by Algorithm 8.2.2. The algorithm inputs the index i, the amount j, the array denom of Algorithm 8.2.2, and the array used computed by Algorithm 8.2.2.

Input Parameters: i,j,denom,usedOutput Parameters: Noneoptimal_coins_set(i,j,denom,used) { if (j == 0) return

if (used[i][j]) { println(“Use a coin of denomination ” + denom[i]) optimal_coins_set(i,j - denom[i],denom,used) } else optimal_coins_set(i + 1,j,denom,used)}

Algorithm 8.3.1 Optimal Matrix MultiplicationThis algorithm computes the minimum number of scalar multiplications to multiply a sequence of n matrices. The input is the array size that contains the sizes of the matrices to be multiplied. The first matrix is size[0] × size[1]; the second is size[1] × size[2]; and so on. The nth matrix is size[n - 1] × size[n]. The output is the array s whose value, s[i][j], is the minimum number of scalar multiplications to multiply matrices i through j. The value ∞ is the largest available integer value.

Input Parameters: sizeOutput Parameters: sopt_matrix_mult(size,s) { n = size.last for i = 1 to n s[i][i] = 0 // w = j - i for w = 1 to n - 1 for i = 1 to n - w { j = w + i s[i][j] = ∞ for k = i to j - 1 { q = s[i][k] + s[k + 1][j] +

size[i - 1] * size[k] * size[j] if (q < s[i][j]) s[i][j] = q } }}

Algorithm 8.4.2 Computing the Length of a Longest Common SubsequenceThis dynamic-programming algorithm computes the length c[i][j] of a longest common subsequence of a[1], ... , a[i] and b[1], ... , b[j] for i = 0, ... , m and j = 0, ... , n.

Input Parameters: a,bOutput Parameters: cLCS(a,b,c) {

m = a.lastn = b.lastfor i = 0 to m

c[i][0] = 0for j = 1 to n

c[0][j] = 0for i = 1 to m

for j = 1 to nif (a[i] != b[j])

c[i][j] = max(c[i - 1][j],c[i][j - 1])else

c[i][j] = 1 + c[i - 1][j - 1]}

Algorithm 8.4.3 Computing a Longest Common SubsequenceThis algorithm uses the array c computed by Algorithm 8.4.2 to output a longest common subsequence. The array a of length m is the first sequence input to Algorithm 8.4.2, and n is the length of the second sequence input to Algorithm 8.4.2.

Input Parameters: a,m (length of a),n (length of second sequence),c (contains lengths of longest common subsequences)Output Parameters: NoneLCS_print(a,m,n,c) {

if (c[m][n] == 0) return if (c[m][n] == c[m - 1][n]) LCS_print(a,m - 1,n,c) else if (c[m][n] == c[m][n - 1]) LCS_print(a,m,n - 1,c) else { LCS_print(a,m - 1,n - 1,c) print(a[m]) }}

Algorithm 8.5.3 Floyd’s Algorithm, Version 1This algorithm computes the length of a shortest path between each pair of vertices in a simple, undirected, weighted graph G. All weights are nonnegative. The input is the adjacency matrix A of G. The output is the matrix A whose ijth entry is the length of a shortest path from vertex i to vertex j.

Input Parameter: AOutput Parameter: Aall_paths(A) { n = A.last for k = 1 to n // compute A(k) for i = 1 to n for j = 1 to n if (A[i][k] + A[k][j] < A[i][j]) A[i][j] = A[i][k] + A[k][j]}

Algorithm 8.5.4 Floyd’s Algorithm, Version 2This algorithm computes the length of a shortest path between each pair of vertices in a simple, undirected, weighted graph G and stores the vertex that follows the first vertex on each shortest path. All weights are nonnegative. The input is the adjacency matrix A of G. The output is the matrix A whose ijth entry is the length of a shortest path from vertex i to vertex j and the matrix next whose ijth entry is the vertex that follows i on a shortest path from i to j.

Input Parameter: AOutput Parameter: A,nextall_paths(A,next) {

n = A.last// initialize next: if no intermediate// vertices are allowed next[i][j] = jfor i = 1 to n

for j = 1 to nnext[i][j] = j

for k = 1 to n // compute A(k) for i = 1 to n for j = 1 to n if (A[i][k] + A[k][j] < A[i][j]) { A[i][j] = A[i][k] + A[k][j]

next[i][j] = next[i][k]

}}

Algorithm 8.5.5 Finding a Shortest PathThis algorithm outputs a shortest path from vertex i to vertex j in a simple, undirected, weighted graph G. It assumes that matrix next has already been computed by Algorithm 8.5.4.

Input Parameters: next,i,jOutput Parameters: Noneprint_path(next,i,j) { // if no intermediate vertices, just

// print i and j and return if (j == next[i][j]) { print(i + “ ” + j) return } // output i and then the path from the vertex // after i (next[i][j]) to j print(i + “ ”) print_path(next,next[i][j],j)}

Algorithm 8.5.12 Warshall’s Algorithm

This algorithm computes the transitive closure of a relation R on {1, ... , n}. The input is the matrix A of R. The output is the matrix A of the transitive closure of R.

Input Parameters: AOutput Parameters: Atransitive_closure(A) {

n = A.lastfor k = 1 to n

for i = 1 to n for j = 1 to n

A[i][j] = A[i][j] (A[i][k] A[k][j])}