HDU 2084 数塔

生)除了校赛,还有什么途径可以申请加入ACM校队? 

数塔

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 33419    Accepted Submission(s): 19960


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

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

已经告诉你了,这是个DP的题目,你能AC吗?
 

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
 

Source
2006/1/15 ACM程序设计期末考试

题目大意:

如题。

思路:

前几个 dp 的题我尽量写的详细一些,把我自己的理解都写在里面,希望对大家理解 dp 有帮助。
在看这一篇之前。我推荐大家先去看一下大白动态规划这一章。
里面那个三角模型,就是这个数塔 ,数塔是接触动态规划最典型最简单的一个例子吧,希望大家好好理解。
大白上说过的一些东西,我就不再继续说了。
还是来讲一组样例哈:
           7
3 8 
8 1 0 
2 7 4 4
4 5 2 6 5

标记 坐标 i 代表行, j 代表此行 的第 j 个数。
那么,大家看哈,从上开始往下走的话,如果是贪心的做法,每次只有两种决策,往左或者往右。
贪心的话,每次取最大的就行啦,但是贪心的做法得到的可能不是整体的最优解,这个大家可以理解吗?
比如
7
1 0
5 2 3
1 2 3 18
最大的明显是 7 - 0 - 3 - 18 这条路,但是贪心却 是走 7 -1 - 5 - 2 。
所以贪心在这里就显得力不从心。那么,应该怎么做呢?
我们不妨建立一个数组,和上个题差不多的思想。
保存每组遍历之和。这样问题可以解决吗?
或者这样说:
借用之前看到的一个资料,形象化一下动态规划。
从前,有一个国王,然后呢,他想从顶部开始往下走,路就是上题中的图。
那么,他要怎么走才能让进过的和最大呢?
他可以找一个大臣,先去谈谈第二行的路,让大臣告诉他走左边的路最后得到的和比较大还是走右边的路得到的和比较大。
那么这个大臣怎么知道第二行的路那条最大呢?
那么他就可以找到他的小伙计,让他的小伙计去第三行探探路,然后让他的小伙计告诉他第二行那条路往第三行走得到的和比较大,并且告诉他最优的第三行的选择。以此类推,那么到了最后一个人的时候,他就不用纠结了对吧,因为不需要往下走了,最大的是哪个,他很清楚,然后他就汇报给他的上一级,然后他的上级再汇报给他的上级,最后汇报到国王那里。
这样,国王就知道了走哪条路是和最大的。


以上呢,就是整个题目的思路。
那么动态转移方程是什么呢?
dp [ i ]  [ j ] + = max ( dp [ i + 1 ] [ j ]  ,  dp [ i + 1 ] [ j + 1 ]  )    i  和 j  表示 i  行  j  列 。

感想:

这个题目非常有用,一定要好好理解。真的。

ac 代码 :

#include
#include
#include
#include
using namespace std;
int main()
{
    int a[110][110];
    int dp[110][110];
    int T,n,i;
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
                scanf("%d",&a[i][j]);
        }
        memset(dp,0,sizeof(dp));
        for(i=n;i>=1;i--)
        {
            for(int j=1;j<=i;j++)
            {
                a[i-1][j]+=max(a[i][j],a[i][j+1]);//这里是倒着推出来的。从后往前 dp  
            }
        }
        cout<


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