Basic
Dynamic Programming

日月卦長

Prerequisite

  • High Dimensional Array
  • Recursion
  • Bitwise operator
  • Math

Fibonacci number

\(F_n = F_{n-1}+F_{n-2}\)
\(F_0=0\\F_1=1\)

Loop

Recursion

long long F[100+5];
// ...
F[0] = 0;
F[1] = 1;
for(int i=2; i<=100; ++i){
    F[i] = F[i-1] + F[i-2];
}
// ...
cout << F[100] << '\n';
long long F(int i){
    if(i == 0) return 0;
    if(i == 1) return 1;
    return F(i-1) + F(i-2);
}
// ...
cout << F(100) << '\n';

Recursion Test

#include <bits/stdc++.h>
using namespace std;
long long F(int i){
    if(i==0 || i==1) return i;
    return F(i-1) + F(i-2);
}
int main(){
    for(int i = 0; i < 50; ++i){
        cout << i << ": " << F(i) << '\n';
    }
    return 0;
}

Recursion Test 2

#include <bits/stdc++.h>
using namespace std;
long long DP[1000];
long long F(int i){
    if(i==0 || i==1) return i;
    if(DP[i]!=0) return DP[i];
    return DP[i] = F(i-1) + F(i-2);
}
int main(){
    for(int i = 0; i < 50; ++i){
        cout << i << ": " << F(i) << '\n';
    }
    return 0;
}

Recursion Test 2

#include <bits/stdc++.h>
using namespace std;
long long DP[1000];
long long F(int i){
    if(i==0 || i==1) return i;
    if(DP[i]!=0) return DP[i];
    return DP[i] = F(i-1) + F(i-2);
}
int main(){
    for(int i = 0; i < 50; ++i){
        cout << i << ": " << F(i) << '\n';
    }
    return 0;
}

sufficient and necessary condition 

of

Dynamic Programming

  • Overlapping subproblems
  • Optimal substructure

Some conditions and transition formula

Overlapping subproblems

$$F_n$$

$$F_{n-1}$$

$$F_{n-2}$$

$$F_{n-2}$$

$$F_{n-3}$$

  • Can be broken down into many subproblems 
  • We call every subproblem:state

Optimal substructure

  • The Answer can be constructed from the answer of subproblems
  • Write them into the formula 
  • State Transition

\(F_0=0\\F_1=1\)

\(F_n = F_{n-1}+F_{n-2}\)

Time Complexity

  • Num of states * Transition Time

\(F_0=0\\F_1=1\)

\(F_n = F_{n-1}+F_{n-2}\)

  • Num of states: \(n\)
  • Transition: \(O(1)\)
  • Total
  • : \(n\times O(1)=O(n)\)

Bottom Up

Top Down

long long F[100+5];
// ...
F[0] = 0;
F[1] = 1;
for(int i=2; i<=100; ++i){
  F[i] = F[i-1] + F[i-2];
}
// ...
cout << F[100] << '\n';
long long DP[100+5];
long long F(int i){
  if(i == 0) return 0;
  if(i == 1) return 1;
  if(DP[i]!=0) return DP[i];
  return DP[i] = F(i-1) + F(i-2);
}
// ...
cout << F(100) << '\n';

Coding

Bottom Up

  • Only loops
  • Run fast
  • Clear Transition
  • Can do more Optimization

Top Down

  • Recursion
  • Run slow
  • Easier to think

Thinking in DP

  1. Feel like DP
  2. State Definition
  3. State Transition based on state definition
  4. Check Time Complexity
  5. Coding

Knapsack Problem

Classic

Knapsack Problem

  • A backpack can hold weight \(T\)
  • There're \(n\) items with weight\(c_1,c_2,\dots,c_n\) respectively
  • Their values are \(w_1,w_2,\dots,w_n\)
  • How much value we can take at most?

State Definition

  • \(d(i,v)\) represent:
    • items from \(1 \sim i\) 
    • Pick some of them into a backpack. It can hold at most weight \(v\). 
    • The largest value it can be

State Transition

  • \(d(i,v)=0\)     if \(i=0\) or \(v = 0\)
  • \(d(i,v)=-\infty\)     if \(v<0\)
  • \(d(i,v)=max(d(i-1,v), d(i-1,v-c_i)+w_i)\)
    if \(i>1\) and \(v > 0\)

 

  • \(d(n,T)\) is the answer!

Time Complexity

  • Num of states: \(n\times T\)
  • Transition Time: \(O(1)\)
  • Total: \(n\times T\times O(1)=O(n\times T)\)

Top Down

int dp[MAXN][MAXT] = {};
bool vis[MAXN][MAXT] = {};

int d(int i, int v){
    if(i==0||v==0) return 0;
    if(v<0) return -9999999;
    if(vis[i][v]) return dp[i][v];
    vis[i][v] = true;
    return dp[i][v] = 
           max(d(i-1,v), d(i-1,v-c[i])+w[i]);
}

Bottom Up

int dp[MAXN][MAXT] = {};

for(int i=1; i<=n; ++i)
    for(int v=c[i]; v<=T; ++v)
        dp[i][v] = 
        max(dp[i-1][v], dp[i-1][v-c[i]]+w[i]);

Reuse Array

int dp[2][MAXT] = {};

for(int i=1; i<=n; ++i)
    for(int v=c[i]; v<=T; ++v)
        dp[i&1][v] = 
        max(dp[(i-1)&1][v], dp[(i-1)&1][v-c[i]]+w[i]);

int ans = dp[n&1][T];

State Compression

int dp[MAXT] = {};

for(int i=1; i<=n; ++i)
    for(int v=T; v>=c[i]; --v)
        dp[v] = max(dp[v], dp[v-c[i]]+w[i]);

int ans = dp[T];

Reference

Practices

BasicDynamicProgramming from SunMoon

By tunchin kao

BasicDynamicProgramming from SunMoon

  • 77