DP-以數塔問題為例分析DP的一些基礎知識
阿新 • • 發佈:2018-12-26
最近看了《演算法筆記》,感覺裡面的動態規劃寫的不錯,綜合自己的感想,寫一寫。DP用來解決最優化問題,而DC是解決問題的。動態規劃將原始的問題分為若干個子問題,通過綜合子問題的最優解,來得到原始問題的最優解。動態規劃會將每個求解過的子問題的解記錄下來,下次遇到同樣的問題,可以直接使用。一般使用遞迴和遞推的寫法來寫動態規劃。
1.遞推
5
8 3
12 7 16
4 10 11 6
從第一層走到第n層,路徑上所有數字相加的和最大是多少。
令dp[i][j](我們稱它為狀態)表示從第i行第j列到最底層的路徑上數字相加得到的最大和。想求出dp[i][j],需求兩個子問題,即從(i+1,j)到達最底層的最大和dp[i+1][j]和從(i+1,j+1)到達最底層的最大和dp[i+1][j+1]。所以dp[i][j]=max(dp[i+1][j+1],dp[i+1][j])+f[i][j](這個方程稱之為狀態轉移方程)。數塔最後一層的dp值,等於元素本身,dp[n][j]=f[n][j],把這種可以直接確定結果的部分稱之為邊界。動態規劃的遞推寫法就是從邊界出發,通過狀態轉移方程擴散到整個dp陣列。
#include<iostream> #include<algorithm> using namespace std; const int maxn=1000; int f[maxn][maxn],dp[maxn][maxn]; int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ cin>>f[i][j]; } } for(intView Codej=1;j<=n;j++){ dp[n][j]=f[n][j]; } for(int i=n-1;i>=1;i--){ for(int j=1;j<=i;j++){ dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+f[i][j]; } } cout<<"最大值:"<<dp[1][1]<<endl; cout<<"最大路徑:"<<f[1][1]; int j=1;for(int i=2;i<=n;i++){ int value=dp[i-1][j]-f[i-1][j]; if(value==dp[i][j]) cout<<"->"<<f[i][j]; else cout<<"->"<<f[i][j+1]; j++; } return 0; }
2遞迴
使用備忘錄的方式對斐波那契數列進行求解。
#include<iostream> #include<vector> using namespace std; vector<int>mem; int F(int n){ if(n==1||n==2) return 1; if(mem[n]!=-1) return mem[n]; else{ mem[n]=F(n-1)+F(n-2); return mem[n]; } } int main(){ int n; cin>>n; mem=vector<int>(n+1,-1); n=F(n); cout<<n; return 0; }View Code