- 動態規划(dynamic progromming)
- 將一個復雜的問題分解成若干個子問題,通過綜合子問題的最優解來得到原問題的最優解
- 動態規划會將每個求解過的子問題的解記錄下來,這樣下一次碰到同樣的子問題時,就可以直接使用之前記錄的結果,而不是重復計算
- 可以用遞歸或者遞推的寫法實現,遞歸的寫法又叫記憶化搜索
- 重疊子問題:如果一個問題可以被分解成若干個子問題,且這些子問題會重復出現,就稱這個問題擁有重疊子問題。 一個問題必須擁有重疊子問題,才能用動態規划去解決。
- 最優子結構:如果一個問題的最優解可以由其子問題的最優解有效地構造出來,那么稱為這個問題擁有的最優子結構。最優子結構保證了動態規划中的原問題的最優解可以由子問題的最優解推導而來
- 動態規划與分治的區別:都是分解為子問題然后合並子問題得到解,但是分治分解出的子問題是不重疊的
- 動態規划與貪心的區別:都有最優子結構,但是貪心直接選擇一個子問題去求解,會拋棄一些子問題,這種選擇的正確性需要用歸納法證明,而動態規划會考慮所有的子問題
- ---------------------------------以上轉載柳神blog------------------------------------
- 我個人的理解就是自底到上 從一個狀態到另一個狀態
- 來看例題http://poj.org/problem?id=1163
- 很典型的dp例題(既可以用dp也可以使用dfs)
-
#include<iostream> using namespace std; int main() { const int inf=105; int n,dp[inf][inf],a[inf][inf]; cin>>n; for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) cin>>a[i][j]; } for(int i=1;i<=n;i++) dp[n][i]=a[n][i]; for(int i=n-1;i>=1;i--) for(int j=1;j<=i;j++) { dp[i][j]=max(a[i][j]+dp[i+1][j],a[i][j]+dp[i+1][j+1]); } cout<<dp[1][1]; return 0; }