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

 

posted @ 2018-12-26 13:23  阳光zfc  阅读(274)  评论(0编辑  收藏  举报