动态规划之数字三角形模型

数字三角形模型:

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

输入格式:

第一行包含整数 n,表示数字三角形的层数;

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

输出格式:

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

思路:

对于三角形中的每个点,如果走到了该点,那么路径中该点的上一个点一定是左上角的点或者是右上角的点;

那么该点的状态一定可以由左上右上两个点的状态推导得到。

从集合的角度考虑:

如果将所有走到 (i,j) 点的路径看做是一个集合,那么该集合可以不重不漏的划分为从左上角走到(i,j) 的路径和从右上角走到 (i,j) 的路径这两个集合;

f[i][j] 表示走到 (i,j) 点的路径中的最大值,a[i][j] 表示 (i,j) 位置的值。

状态转移方程如下:

f[i][j] = max(f[i - 1][j], f[i - 1][j + 1]) + a[i][j]

因为终点在最后一行,所以我们在三角形的最后一行中寻找最大值即可。

注意这里有边界的问题:要保证左上的点和右上的点没有越界才走,并且必须要选择一个点,故可以选择将所有点的初始状态取INF,特别的 f[1][1] = g[1][1]。

数字三角形问题一般求的是最大/小值,一般都有边界问题,在更新边界上的值得时候不要被边界外的值影响。

代码模板如下:

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

const int N = 510;
int g[N][N], f[N][N];//三角形,以每个点为终点的路径的最大值
int n;

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)//读入地图(其实可以在读入的时候就处理,这里将读入和处理分开了)
        for (int j = 1; j <= i; j++)
            cin >> g[i][j];

    memset(f, -0x3f, sizeof f);//初始化
    f[1][1] = g[1][1];

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= i; j++) {
            if (j - 1 >= 1)f[i][j] = max(f[i][j], f[i - 1][j - 1] + g[i][j]);//如果左上角未越界
            if (j < n)f[i][j] = max(f[i][j], f[i - 1][j] + g[i][j]);//如果右上角未越界
        }

    int res = -0x3f3f3f3f;//在最后一行中找最大值
    for (int i = 1; i <= n; i++)res = max(res, f[n][i]);

    cout << res;
    return 0;
}

例题1 . 摘花生:

1015. 摘花生 - AcWing题库

思路:

每个点的状态由右边或者是上边的点转移得到;

状态转移方程:

f[i][j] = max(f[i - 1][j], f[i][j - 1]) + g[i][j]

AC代码如下:

#include<iostream>
using namespace std;

const int N = 1010;
int f[N][N];
int T, n, m;

int main() {
    cin >> T;

    while (T--) {
        cin >> n >> m;

        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                cin >> f[i][j];
                f[i][j] = max(f[i - 1][j], f[i][j - 1]) + f[i][j];
            }

        cout << f[n][m] << endl;
    }

    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值