杭电2084--数塔问题

十多天没被acm虐了,有点手痒,把之前做过的动规数塔题重新看了一遍,写一下心得。
题目描述:
这里写图片描述
解析:
一般的想法:首先,我们可以试一下使用传统的遍历。既然求经过结点的数字之和的MAX,不妨将所有情况列出,最后比较各数字和的大小即可,这样的方法显然超时,因为在计算不同的分支时,存在大量不必要的重复计算,例如在进行最后一层的计算时,有两种路径:
(1)9+12+10+2+19
(2)9+12+10+2+7
仅仅是最后的元素不一样,可是计算的时候前面四个数的加和却计算了两遍,其他的遍历途径同理。

或者有一种想法,也就是从上往下计算每层的最大值,并在这层所属的下一层的两个元素间选最大,以此类推。比如:
9–15–8–9–10,这样的做法也是不对的,例如对于15所属的下面两个元素6和8,虽然6比8小,但是(6+18)大于(8+9),因此这种方法更不可取。
动态规划:
既然上述两个方法均不可取,我们就可以引入动态规划来做。动态规划通过把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。 观察问题我们不难发现,这道题的解法就是在不断反复的计算各阶段的最优解,最后由单阶段最优解汇总为整体最优。
为了计算的方便,我们从下往上思考这个问题。单阶段最优解其实就是上个阶段的最优解加上本阶段的值。用dp[i][j]来表示i行j列元素的最优解,不难列出状态转移方程:

dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];

局部最优解从下向上依次汇总,在第二层的时候变为2个子解之间的最优解,便得出了最终结果。
通过动态规划的思想,保证了每个过程只计算一遍,不存在重复计算的问题。

代码部分:

#include<stdio.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    int i,j,n,t;
    int a[102][102];
    int dp[102][102];
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            scanf("%d",&n);
            for(i=1;i<=n;i++)
            for(j=1;j<=i;j++)
                scanf("%d",&a[i][j]);
            for(i=1;i<=n;i++)
                dp[n][i]=a[n][i];
            for(i=n-1;i>=1;i--)
            {
                for(j=1;j<=i;j++)
                dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
            }
            printf("%d\n",dp[1][1]);        
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cprimesplus/article/details/82385594