动态规划——相关概念,(数塔问题)

  • Post author:
  • Post category:其他


与动态规划有关的几个概念:



  • 记忆化搜索:对于有重叠子问题的问题,我们把第一次遇到的子问题的值给记录下来,下一次遇到这个相同的子问题时直接使用这个值,这也是这个递归函数开一个二维数组 的作用;



  • 重叠子问题:一个问题可以划分为若干个子问题,这些子问题又会重复出现;



  • 最优子结构:如果一个问题的最优解可以由子问题的解构造出来;



  • 状态无后效性:当前状态记录了历史信息,一旦当前状态确定了,就不会再改变,且未来的决策只能在已有的一个或若干个状态的基础上进行,历史信息只能通过已有的状态去影响未来的决策。(PS:《算法笔记》)

给出一个经典问题——数塔问题:一共给出了几个程序,有直解输出结果的,还有给出最大值的路径的,也有递归求解的,还有递推求解的:

/**
    数塔问题,
    状态转移方程:dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+f[i][j];
    最优子结构:如果一个问题的最优解可以由子问题的解构造出来;
    1)只输出结果;
    data:
        5
        5
        8 3
        12 7 16
        4 10 11 6
        9 5 3 9 4

        5
        5
        8 3
        12 7 105
        4 10 11 6
        78 5 3 9 4
*/

/**
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    cout << "输入塔的层数:\n";
    cin >> n;
    int f[n+1][n+1],dp[n+1][n+1];
    printf("输入%d层塔的值\n",n);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=i;++j)
            cin >> f[i][j];
    for(int i=1;i<=n;++i)
        dp[n][i]=f[n][i];
    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;
    return 0;
}
*/

递归解决:

  • /**
        2)递归解决
    */
    /**
        记忆化搜索:对于有重叠子问题的问题,我们把第一次遇到的子问题的值给记录下来,
        下一次这个相同的子问题时遇到直接使用这个值,这也是这个递归函数开一个二维数组
        的作用;
    
        重叠子问题:一个问题可以划分为若干个子问题,这些子问题又会重复出现;
        
        最优子结构:如果一个问题的最优解可以由子问题的解构造出来;
    */
    
    /**
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn=10;
    int f[maxn][maxn],dp[maxn][maxn];
    int n;
    int max_val(int pos,int index)
    {
        memset(*dp,-1,sizeof(dp));
        if(pos==n)
            return f[pos][index]; //如果达到最后一层,返回这个元素的值
        if(dp[pos][index]!=-1)
            return dp[pos][index];
        else
        {
            dp[pos][index]= max(max_val(pos+1,index),max_val(pos+1,index+1))+f[pos][index]; //如果要选这个元素,
            return dp[pos][index];  //则比较下一层紧挨着的两个元素的及后续选择的最大的和,谁大选谁
    
        }
    }
    int main()
    {
        cout << "输入塔的层数:\n";
        cin >> n;
        printf("输入%d层塔的值\n",n);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=i;++j)
                cin >> f[i][j];
        cout << max_val(1,1) << endl;
        return 0;
    }
    */

输出最大值的路径:

/**
    3)输出最大值的路径
*/

/**
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    cout << "塔的层数:\n";
    cin >> n;
    int f[n+1][n+1],dp[n+1][n+1];
    for(int i=1;i<=n;++i)
        for(int j=1;j<=i;++j)
            cin >> f[i][j];
    for(int i=1;i<=n;++i)
        dp[n][i]=f[n][i];
    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 << "maximum result:\n" << dp[1][1] << endl;
    cout << "path of maxmium:\n" ;
    cout << f[1][1];
    for(int i=1,j=1;i<n;++i)
    {
        cout << " -> ";
        int temp=dp[i][j]-f[i][j];
        if(temp==dp[i+1][j])
            cout << f[i+1][j];
        else
            cout << f[i+1][++j];
    }
    cout << endl;
    return 0;
}
*/

三维数组存储数据,存储,中间处理,输出于一体

/**
    三维数组存储数据,存储,中间处理,输出于一体
*/


#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    cout << "塔的层数:\n";
    cin >> n;
    int a[n+1][n+1][3];
    for(int i=1;i<=n;++i)
        for(int j=1;j<=i;++j)
        {
            cin >> a[i][j][0];
            a[i][j][2]=0;   //假设每一层都选择下一层的左边个元素
        }
    for(int i=1;i<=n;++i)
        a[n][i][1]=a[n][i][0];
    for(int i=n-1;i>=1;--i)
        for(int j=1;j<=i;++j)
    {
        a[i][j][1]=max(a[i+1][j][1],a[i+1][j+1][1])+a[i][j][0];
        if(a[i+1][j][1]<a[i+1][j+1][1])
            a[i][j][2]=1;   //如果下一层的右边元素更优,则置为1,选择下一层的右边个元素
    }

    cout << "maximum result:\n" << a[1][1][1] << endl;
    cout << "path of maxmium:\n" ;
    int i,j;
    for( i=1,j=1;i<=n;++i)
    {
        cout << a[i][j][0];
        if(i!=1||i!=n)
            cout << " -> ";
        j+=a[i][j][2];
    }
    return 0;
}



版权声明:本文为qq_51825761原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。