1. 程式人生 > >DP-以數塔問題為例分析DP的一些基礎知識

DP-以數塔問題為例分析DP的一些基礎知識

  最近看了《演算法筆記》,感覺裡面的動態規劃寫的不錯,綜合自己的感想,寫一寫。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(int
j=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; }
View Code

  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