P1216 [IOI1994][USACO1.5]数字三角形 Number Triangles

题目描述
观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

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

在上面的样例中,从7→3→8→7→5 的路径产生了最大

输入格式
第一个行一个正整数 r ,表示行的数目。后面每行为这个数字金字塔特定行包含的整数。

输出格式
单独的一行,包含那个可能得到的最大的和。

输入输出样例
输入 #1

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

输出 #1

30

说明/提示
【数据范围】
对于100% 的数据,1≤r≤1000,所有输入在 [0,100]范围内。

题目翻译来自NOCOW。

USACO Training Section 1.5

IOI1994 Day1T1

思路分析

因为从最高点到底部的最大和,可以等于max(左边的点到底部的最大和,右边的点到底部的最大和)加上该数字本身。即原问题可以化为同样形式且规模更小的问题(该问题具有最优子结构性质)。而且底部那一层到底部的最大和等于该数本身(因为该层无法再向下走),所以就解决了动态规划的初始值问题。
递推式
maxsum[i][j] =num[i][j];   i=r
maxsum[i][j] = max(maxsum[i+1][j],maxsum[i+1][j+1]) + num[i][j];    i<r

注意点

  1. 为了防止数组越界存储数字的数组可以开大一点点。

代码

#include <iostream>
using namespace std;
int maxsum[1005][1005];//maxsum[i][j]代表第i行第j列的数到底部任意处结束经过数字的最大和
int main()
{
    int r;
    cin>>r;
    int num[r+5][r+5];//注意要留出多一些空间
    for(int i=1;i<=r;i++)
        for(int j=1;j<=i;j++)
            cin>>num[i][j];
    for(int j=1;j<=r;j++)
        maxsum[r][j] = num[r][j];//底部那一层数字到底部的最大和等于其本身
    for(int i=r-1;i>0;i--){
        for(int j=1;j<=i;j++){
            //maxsum[i][j]到达到底部任意处结束经过数字的最大和等于max(左边的点到底部的最大和,右边的点到底部的最大和)加上该数字本身
            maxsum[i][j] = max(maxsum[i+1][j],maxsum[i+1][j+1]) + num[i][j];
        }
    }
    cout<<maxsum[1][1]<<endl;//输出最高点到底部的最大和
    return 0;
}

扩展知识点

  1. 一定要用二维数组来存最大和吗?
    想明白了吗?小靓仔(女)!!!
    答案是不需要的。可以用一维数组来存最大和,因为在求maxsum[i][j]时,maxsum[i+1][j]用过之后就不会在使用了,所以可以将这个值覆盖,综上所述可以用一维数组来存储最大和。

代码

#include <iostream>
using namespace std;
int maxsum[1005];
int main()
{
    int r;
    cin>>r;
    int num[r+5][r+5];//注意要留出多一些空间
    for(int i=1;i<=r;i++)
        for(int j=1;j<=i;j++)
            cin>>num[i][j];
    for(int j=1;j<=r;j++)
        maxsum[j] = num[r][j];
    for(int i=r-1;i>0;i--){
        for(int j=1;j<=i;j++){
            maxsum[j] = max(maxsum[j],maxsum[j+1]) + num[i][j];
        }
    }
    cout<<maxsum[1]<<endl;//输出最高点到底部的最大和
    return 0;
}
  1. 一定要另外开辟空间来存储最大和?
    想明白了吗?小靓仔(女)!!!
    答案是不需要另外开辟空间的。可以用存储数字的数组的最后一行来存最大和,因为在求maxsum[i][j]时,num[i][j]用过之后就不会在使用了,所以可以将这个值覆盖,综上所述可以用存储数字的数组的最后一行来存最大和。

代码

#include <iostream>
using namespace std;
int main()
{
    int r;
    cin>>r;
    int num[r+5][r+5];//注意要留出多一些空间
    for(int i=1;i<=r;i++)
        for(int j=1;j<=i;j++)
            cin>>num[i][j];
    for(int i=r-1;i>0;i--){
        for(int j=1;j<=i;j++){
            num[r][j] = max(num[r][j],num[r][j+1]) + num[i][j];
        }
    }
    cout<<num[r][1]<<endl;//输出最高点到底部的最大和
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值