蓝桥杯——数字三角形

题目描述:

上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。

路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。

题目路径:https://www.lanqiao.cn/problems/505/learning/

输入描述

输入的第一行包含一个整数N (1≤N≤100),表示三角形的行数。

下面的 N 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。

输出描述

输出一个整数,表示答案。

输入输出样例

示例

输入:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

 输出

27

分析:

我们可以很容易的得知要使用动态规划来解这道题,与一般三角形求值不同,这道题有一个限制条件。 

向左下走的次数与向右下走的次数相差不能超过 1 。因此我们不仅要记录到达每一个点的最大值为多少,还要记录到达这个点的left与right的值为多少。

因此我们可以得知需要定义四个二维数组num[110][110],dp[110][110],left[110][110],right[110][110];

    int dp[110][110]; //dp用于储存到达某一点时的最大和
    int n;
    cin >> n;
    // num数组用于储存值,left储存从到达某一点时一共向左下走了多少次,right储存到达某一点时向右下走了多少次
    int num[110][110], left[110][110], right[110][110]; 
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            cin >> num[i][j];
            left[i][j] = 0;       //将每一个点的left与right都初始化为0;
            right[i][j] = 0;
        }
    }

 核心代码:

    dp[1][1] = num[1][1];  //因为第一行只有一个数,我们首先将dp[1][1]初始化为num[1][1]
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            //如果 j=1 的时候也就是说num[i][j]在第i行的最左边,因此只能由上一行向左下到达
            if (j == 1)     
            {
                dp[i][j] = dp[i - 1][j] + num[i][j];
                //上一行走左下的路径,因此到达次点时向左下走的路径为到达上一行的左下路径+1;
                left[i][j] = left[i - 1][j] + 1;  
                //让这个点的right等于到达这个点的上一个点的right    
                right[i][j] = right[i - 1][j];
            }
               //当j = i时在最右边类比最左边的情况
            else if (j == i)
            {
                dp[i][j] = dp[i - 1][i - 1] + num[i][j];
                right[i][j] = right[i - 1][i - 1] + 1;
                left[i][j] = left[i - 1][i - 1];
            }
                //当j既不在最左边也不再最右边的时候
            else
            {
                  //因为求得是最大值,因此需要求从右上和左上分别到达此点时的值,并取最大值
                dp[i][j] = max(dp[i - 1][j] + num[i][j], dp[i - 1][j - 1] + num[i][j]);
                //当最大值为从右上点到达时(既右上的点往左下走到达的此点)left++
                if (dp[i][j] == dp[i - 1][j] + num[i][j])
                {
                    left[i][j] = left[i - 1][j] + 1;
                    right[i][j] = right[i - 1][j];
                }
                //当最大值为从左上点到达时(既左上的点往右下走到达的此点)right++
                else
                {
                    right[i][j] = right[i - 1][j - 1] + 1;
                    left[i][j] = left[i - 1][j - 1];
                }
            }
        }
    }

当到达所有点的最大值都求出之后我们需要取出向左下走的次数与向右下走的次数相差不能超过1的点。

    int x[110]; //储存相差不超过一的点的值
    int m = 0;
    for (int i = 1; i <= n; i++) 
    {
        // n 为我们所输入的行数,因为到达第n行所以只需要枚举第n行的dp值即可
        if (abs(left[n][i] - right[n][i]) <= 1) //求出相差不超过1的点
            x[m++] = dp[n][i]; 
    }
    int Max = 0; //用Max储存最大dp值
    for (int i = 0; i < m; i++)
    {
        if (x[i] > Max)
            Max = x[i];
    }

完整代码:

#include 
#include
#include
#include
using namespace std;
int main()
{
    int dp[110][110];
    int n;
    cin >> n;
    int num[110][110], left[110][110], right[110][110];
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            cin >> num[i][j];
            left[i][j] = 0;
            right[i][j] = 0;
        }
    }

    dp[1][1] = num[1][1];
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            if (j == 1)
            {
                dp[i][j] = dp[i - 1][j] + num[i][j];
                left[i][j] = left[i - 1][j] + 1;
                right[i][j] = right[i - 1][j];
            }
            else if (j == i)
            {
                dp[i][j] = dp[i - 1][i - 1] + num[i][j];
                right[i][j] = right[i - 1][i - 1] + 1;
                left[i][j] = left[i - 1][i - 1];
            }
            else
            {
                dp[i][j] = max(dp[i - 1][j] + num[i][j], dp[i - 1][j - 1] + num[i][j]);
                if (dp[i][j] == dp[i - 1][j] + num[i][j])
                {
                    left[i][j] = left[i - 1][j] + 1;
                    right[i][j] = right[i - 1][j];
                }
                else
                {
                    right[i][j] = right[i - 1][j - 1] + 1;
                    left[i][j] = left[i - 1][j - 1];
                }
            }
        }
    }

    int x[110];
    int m = 0;
    for (int i = 1; i <= n; i++)
    {
        if (abs(left[n][i] - right[n][i]) <= 1)
            x[m++] = dp[n][i];
    }
    int Max = 0;
    for (int i = 0; i < m; i++)
    {
        if (x[i] > Max)
            Max = x[i];
    }
    cout << Max;
    return 0;
}

 

 

你可能感兴趣的:(动态规划,动态规划)