基礎DP

什麼是DP?

舉個例子

費波那契數列

由0和1開始

之後由前兩位數字相加而得出

第n項為第n-1和第n-2項的總和

用遞迴試試

示意圖

#include <iostream>
using namespace std;
long long f(int n){
	if(n == 1) return 1;
	else if(n == 2) return 2;
	return f(n-1) + f(n-2);
}
int main(){
	int n;
	cin >> n;
	cout << f(n) << '\n';
	return 0;
}
# PRESENTING CODE

Code

可以,但是很慢,複雜度是O(2^n)

如果把算過的記下來,那就不用重複算,

也就是以空間換取時間

示意圖

# PRESENTING CODE

Bottom up

#include <iostream>
using namespace std;
const int MAXN = 1e6+5
long long dp[MAXN];
long long f(int n){
  if(dp[n]) return dp[n];
  if(n <= 2) return dp[n] = n;
  return dp[n] = f(n-1) + f(n-2);
}
int main(){
  int n;
  cin >> n;
  cout << f(n) << '\n';
}
#include <iostream>
using namespace std;
const int MAXN = 1e6+5
long long dp[MAXN];
int main(){
  int n;
  cin >> n;
  dp[1] = 1;
  dp[2] = 2;
  for(int i=3; i<=n; ++i)
    dp[i] = dp[i-1] + dp[i-2];
  cout << dp[n] << '\n';
}

Top down

使用迴圈

從邊界出發

由下到上計算

 

使用遞迴

由上到下計算

Bottom up

Top down

DP的特性

  • 將大問題切割成多個小問題,再將小問題的解答組合起來
  • 最佳子結構:最佳解可以從子問題的最佳解推算
  • 重疊子問題:子問題重複計算
  • 無後效性:子問題的解確定後不會再被影響

步驟

  1. 定義狀態
  2. 推轉移式/遞迴式
  3. 打邊界
  4. 實現

實作

   2
  3 4
 6 5 7
4 1 8 3
# PRESENTING CODE

定義狀態

若在(i, j),

則必定經過(i-1, j)

或(i-1, j-1)

推轉移式

dp[i][j] = min( dp[ i - 1 ][ j - 1 ], dp[ i - 1 ][ j ] ) + triangle[ i ][ j ]

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {

        vector<vector<int>> dp(triangle.size(), vector<int>(triangle.size(), 0));    //走到(i, j)位置上的最小路径和

        dp[0][0] = triangle[0][0];

        //初始化第一列和最后一列
        for(int i = 1; i < triangle.size(); i++){

            dp[i][0] = dp[i - 1][0] + triangle[i][0];
            dp[i][triangle[i].size() - 1] = dp[i - 1][triangle[i - 1].size() - 1] + triangle[i][triangle[i].size() - 1];
        }

        for(int i = 1; i < triangle.size(); i++){

            for(int j = 1; j < i; j++){

                dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle[i][j];
            }
        }

        int res = INT_MAX;
        for(int i = 0; i < triangle[triangle.size() - 1].size(); i++){

            res = min(res, dp[triangle.size() - 1][i]);
        }
        
        return res;
    }
};
# PRESENTING CODE

Code

參考資料

Code

By ivanlo

Code

  • 24