• Solve sub-problems just once and save answers in a table
  • Use a table instead of recursion

Fibonacci Numbers

F(N)=F(N1)+F(N2)F(N)=F(N-1)+F(N-2)

1
2
3
4
5
int Fib(int N) 
{
if (N <= 1) return 1;
else return Fib(N-1)+Fib(N-2);
}

T(N)T(N1)+T(N2)T(N)F(N)T(N)\geq T(N-1)+T(N-2)\rarr T(N)\geq F(N)

image-20210428214438965

  • Trouble maker: The growth of redundant calculations is explosive.
  • Solution: Record the two most recently computed values to avoid recursive calls.
1
2
3
4
5
6
7
8
9
10
11
12
13
int Fibonacci(int N) 
{
int i, Last, NextToLast, Answer;
if (N <= 1) return 1;
Last = NextToLast = 1; /*F(0) = F(1) = 1*/
for (i = 2; i <= N; i++)
{
Answer = Last+NextToLast; /*F(i) = F(i-1) + F(i-2)*/
NextToLast = Last;
Last = Answer; /*update F(i-1) and F(i-2)*/
} /* end-for */
return Answer;
}

T(N)=O(N)T(N)=O(N)

Ordering Matrix Multiplications

  • The problem is to find the order that we can compute the product of nn matrices with minimal computing time
  • Let bnb_n = number of different ways to compute M1M2MnM_1\cdot M_2\cdots M_n. Then we have b2=1,b3=2,b4=5,b_2 = 1, b_3 = 2, b_4 = 5,\cdots
  • Let Mij=MiMjM_{ij}=M_i\cdots M_j. Then M1n=M1Mn=M1iMi+1nM_{1n}=M_1\cdots M_n=M_{1i}\cdot M_{i+1n}
  • Catalan number

bn=i=1n1bibni=O(4nnn)where n>1 and b1=1b_n=\sum^{n-1}_{i=1}b_ib_{n-i}=O(\frac{4^n}{n\sqrt n})\quad\text{where $n>1$ and $b_1=1$}

  • Suppose we are to multiply nn matrices M1MnM_1\cdots M_n where MiM_i is an ri1×rir_{i-1}\times r_i matrix. Let mijm_{ij} be the cost of the optimal way to compute M1MnM_1\cdots M_n where MiM_i. Then we have the recurrence equations:

    mij={0,if i=jminil<j{mil+ml+1j+ri1rlrj},if i<jm_{ij}= \begin{cases} 0, & \text{if $i=j$} \\ \min_{i\leq l<j}\{m_{il}+m_{l+1j}+r_{i-1}r_lr_j\}, & \text{if $i<j$} \end{cases}

  • There are only O(N2)O(N^2) values of MijM_{ij}

  • If ji=kj-i=k, then the only values MxyM_{xy} required to compute MijM_{ij} satisfy yx<ky-x<k

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*r contains number of columns for each of the N matrices*/ 
/*r[0] is the number of rows in matrix 1*/
/*Minimum number of multiplications is left in M[1][N]*/
void OptMatrix(const long r[ ], int N, TwoDimArray M)
{
int i, j, k, L;
long ThisM;
for(i = 1; i <= N; i++) M[i][i] = 0;
for(k = 1; k < N; k++) /*k = j-i*/
for(i = 1; i <= N-k; i++) /* For each position */
{
j = i + k;
M[i][j] = Infinity;
for( L = i; L < j; L++ )
{
ThisM = M[ i ][ L ] + M[ L + 1 ][ j ] + r[ i - 1 ] * r[ L ] * r[ j ];
if ( ThisM < M[ i ][ j ] ) /* Update min */
M[ i ][ j ] = ThisM;
} /* end for-L */
} /* end for-Left */
}

T(N)=O(N3)T(N)=O(N^3)

Optimal Binary Search Tree

  • The best for static searching (without insertion and deletion)

  • Given NN words w1<w2<<wNw_1 < w_2 < \cdots < w_N, and the probability of searching for each wiw_i is pip_i. Arrange these words in a binary search tree in a way that minimize the expected total access time

    T(N)=i=1Npi(1+di)T(N)=\sum^N_{i=1}p_i\cdot(1+d_i)

image-20210429120035275

image-20210429120124448 image-20210429121257965

image-20210429121322733

cij=pk+cost(L)+cost(R)+weight(L)+weight(R)=pk+ci,k1+ck+1,j+wi,k1+wk+1,j=wij+ci,k1+ck+1,jc_{ij}=p_k+\text{cost}(L)+\text{cost}(R)+\text{weight}(L)+\text{weight}(R)\\ =p_k+c_{i,k-1}+c_{k+1,j}+w_{i,k-1}+w_{k+1,j}=w_{ij}+c_{i,k-1}+c_{k+1,j}

  • TijT_{ij} is optimal \rarr rij=kr_{ij}=k such that cij=mini<lj{wij+ci,l1+cl+1,j}c_{ij}=\min_{i<l\leq j}\{w_{ij}+c_{i,l-1}+c_{l+1,j}\}

image-20210429135228768

T(N)=O(N3)T(N)=O(N^3)

Floyd Shortest Path Algorithm

  • For all pairs of viv_i and vj(ij)v_j ( i \neq j ), find the shortest path between.

Method 1

  • Use single-source algorithm for |V| times
  • T=O(V3)T=O(|V|^3) —— works fast on sparse graph

Method 2

  • Define Dk[i][j]=min{length of path i{lk}j}D^k[i][j]=\min\{\text{length of path }i\rarr\{l\leq k\}\rarr j\} and D1[i][j]=Cost[i][j]D^{-1}[i][j]=\text{Cost}[i][j]. Then the length of the shortest path from ii to jj is DN1[i][j]D^{N-1}[i][j]

Algorithm

  • Start from D1D^{-1} and successively generate D0,D1,,DN1D^0,D^1,\cdots,D^{N-1}. If Dk1D^{k-1} is done, then either
    • kk\notin the shortest path i{lk}ji\rarr\{l\leq k\}\rarr j, then Dk=Dk1D^k=D^{k-1}
    • kk\in the shortest path $i\rarr{l\leq k}\rarr j = {\text{the shortest path from ii to kk}}\cup{\text{the shortest path from kk to jj}}$, then Dk[i][j]=Dk1[i][k]+Dk1[k][j]D^k[i][j]=D^{k-1}[i][k]+D^{k-1}[k][j]
  • Dk[i][j]=min{Dk1[i][j],Dk1[i][k]+Dk1[k][j]},k0D^k[i][j]=\min\{D^{k-1}[i][j],D^{k-1}[i][k]+D^{k-1}[k][j]\},k\geq0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*A[ ] contains the adjacency matrix with A[i][i] = 0*/ 
/*D[ ] contains the values of the shortest path*/
/*N is the number of vertices*/
/*A negative cycle exists iff D[i][i] < 0*/
void AllPairs(TwoDimArray A, TwoDimArray D, int N)
{
int i, j, k;
for (i = 0; i < N; i++) /*Initialize D*/
for(j = 0; j < N; j++)
D[i][j] = A[i][j];
for(k = 0; k < N; k++) /*add one vertex k into the path*/
for(i = 0; i < N; i++)
for(j = 0; j < N; j++)
if(D[i][k]+D[k][j] < D[i][j])
D[i][j] = D[i][k]+D[k][j]; /* Update shortest path */
}
  • T(N)=O(N3)T(N)=O(N^3), but faster in a dense graph.
  • Works if there are negative edge costs, but no negative-cost cycles.

Design a DP method

  • Characterize an optimal solution
  • Recursively define the optimal values
  • Compute the values in some order
  • Reconstruct the solving strategy

image-20210511190733661

The correct answer is C.