舉個例子
由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
可以,但是很慢,複雜度是O(2^n)
如果把算過的記下來,那就不用重複算,
也就是以空間換取時間
示意圖
# PRESENTING CODE
#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';
}
使用迴圈
從邊界出發
由下到上計算
使用遞迴
由上到下計算
DP的特性
步驟
實作
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
參考資料