动态规划入门——HUDU 2084 数塔

来源:互联网 发布:java批量发送邮件 编辑:程序博客网 时间:2024/05/20 14:23

Problem Description
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

这里写图片描述

Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。

Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。

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

Sample Output
30

题目分析: 可以用一个二维数组f[i][j]来保存数塔,i代表数塔的第i行, j代表第i行上一共有j个数. f[i][j]代表扫描到第i行的第j个为止的最大和. 很容易得到状态转移公式: f[i][j] += max(f[i+1][j],f[i+1][j+1])

代码如下:

# include <stdio.h># include <string># include <algorithm>using namespace std;# define MAX 500int main(void){    int f[MAX][MAX];    int t,n,i,j;    scanf("%d",&t);    while (t--)    {        memset(f,0,sizeof(f));        scanf("%d",&n);        for ( i=0; i<n; ++i )            for ( j=0; j<=i; ++j )                scanf("%d",&f[i][j]);        for ( i=n-2; i>=0; --i )            for ( j=0; j<=i; ++j )                f[i][j] += max(f[i+1][j+1],f[i+1][j]);         printf("%d\n",f[0][0]);    }    return 0;}

本题也可以自顶向下来扫描, 代码如下:

# include <stdio.h># include <string># include <algorithm>using namespace std;# define MAX 500int main(void){    int f[MAX][MAX];    int t,n,i,j;    int    m;      scanf("%d",&t);    while (t--)    {        m=-10;           memset(f,0,sizeof(f));        scanf("%d",&n);        for ( i=0; i<n; ++i )            for ( j=0; j<=i; ++j )                scanf("%d",&f[i][j]);        for ( i=1; i<n; ++i )   //首先将边界的最大和更新一遍        {            f[i][0]+=f[i-1][0];              f[i][i]+=f[i-1][i-1];        }        for ( i=2; i<n; ++i ) //因为边界的值已更新好,所以i从第三行开始 , 为什么不是第二行?因为第二行只有两个数,都已经被更新好了            for ( j=1; j<i; ++j ) //因为边界的值更新好,所以从第二个数扫描到倒数第二个数                f[i][j] += max(f[i-1][j-1],f[i-1][j]);        for ( j=0; j<n; ++j ) //此时的f数组中的最后一行已经保存了每一种相加情况的和,现在找出最大值            if ( m<f[n-1][j] )                 m = f[n-1][j];         printf("%d\n",m);    }    return 0;}
0 0