AcWing898_数字三角形

AcWing898.数字三角形

题目链接:AcWing898.数字三角形

1. 题目描述

给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

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

输入格式
第一行包含整数n,表示数字三角形的层数。
接下来n行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

输出格式
输出一个整数,表示最大的路径数字和。

数据范围
1 ≤ n ≤ 500 1≤n≤500 1n500,
− 10000 ≤ 三 角 形 中 的 整 数 ≤ 10000 −10000 ≤ 三角形中的整数≤10000 1000010000

输入样例:

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

输出样例:

30
2. 解题思路

首先,对于题目中的任意一点,都有很多种走法。说明,这个题目中,每个结点对应的路径值都会包含能走到该结点的前一个结点路径值,即从 ( 1 , 1 ) → ( i , j ) (1,1) \rightarrow (i,j) (1,1)(i,j)一定包含 ( 1 , 1 ) → ( i − 1 , j ) (1,1) \rightarrow (i - 1, j) (1,1)(i1,j),所以在计算时,如果使用暴力破解的方法,会使本题的复杂度变成指数级,所以使用动态规划算法可以降低时间复杂度。
D P { 状 态 表 示 f ( i , j ) { 集 合 : 所 有 从 ( 1 , 1 ) 走 到 ( i , j ) 走 法 的 集 合 属 性 : m a x ( 路 径 上 权 值 的 最 大 值 ) 状 态 计 算 : 对 于 ( i , j ) 可 以 从 ( i − 1 , j ) 和 ( i − 1 , j − 1 ) 转 移 过 来 ,                     即 ( 1 , 1 ) → ( i − 1 , j ) → ( i , j ) , 前 一 步 部 分 正 好 表 示 的 是 f ( i − 1 , j ) ,                     同 理 ( i − 1 , j − 1 ) 这 个 点 可 以 表 示 为 f ( i − 1 , j − 1 ) 。                     两 者 取 一 个 m a x , 再 加 上 w ( i , j ) 的 值 即 可 得 到 f ( i , j ) 的 结 果 。 DP\begin{cases} 状态表示 f(i,j) \begin{cases} 集合:所有从(1, 1)走到(i, j)走法的集合 \\ \\ 属性:max (路径上权值的最大值) \end{cases}\\ \\ 状态计算: 对于(i, j)可以从(i - 1, j)和(i - 1, j - 1)转移过来,\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 即(1, 1) \rightarrow (i - 1, j) \rightarrow (i, j), 前一步部分正好表示的是f(i - 1, j), \\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 同理(i - 1, j - 1)这个点可以表示为f(i - 1, j - 1)。\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 两者取一个max,再加上w(i, j)的值即可得到f(i, j)的结果。 \end{cases} DPf(i,j)(1,1)(i,j)max():(i,j)(i1,j)(i1,j1)                   (1,1)(i1,j)(i,j),f(i1,j),                   (i1,j1)f(i1,j1)                   maxw(i,j)f(i,j)
最后答案是 max ⁡ 1 ≤ i ≤ n { f ( n , i ) } \max_{1 \leq i \leq n}\{f(n, i)\} max1in{f(n,i)}

3. 代码实现
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510;

int n;
int w[N][N];
int f[N][N];

int main()
{
    scanf("%d", &n);
   
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            cin >> w[i][j];
            
    memset(f, -0x3f, sizeof f);
    f[1][1] = w[1][1];
    for (int i = 2; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            f[i][j] = max(f[i - 1][j], f[i - 1][j - 1]) + w[i][j];
    
    int res = -0x3f3f3f3f;
    for (int i = 1; i <= n; i ++ )
        res = max(res, f[n][i]);
    
    printf("%d\n", res);
    return 0;
} 
4. 注意事项
  1. 初始化
    因为,本题状态更新时,在第一列会出现非法状态向合法状态转移的情况,所以要注意数组的初始化。由于本题有负数,所以只需要将数组中所有元素初始化成负无穷即可(也可以单独初始化)。
  2. 一定注意在求res这个结果时,要初始化成负无穷,否则无法求出正确的值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值