# [USACO1.5][IOI1994]数字三角形 Number Triangles
## 题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。```cpp
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
```
在上面的样例中,从 $7 \to 3 \to 8 \to 7 \to 5$ 的路径产生了最大## 输入格式
第一个行一个正整数 $r$ ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
## 输出格式
单独的一行,包含那个可能得到的最大的和。
## 样例 #1
### 样例输入 #1
```
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
```### 样例输出 #1
```
30
```## 提示
【数据范围】
对于 $100\%$ 的数据,$1\le r \le 1000$,所有输入在 $[0,100]$ 范围内。题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
1.这个题目也是动态规划。
2.可以开二维数组,建议用一维哦。一维也是特别好理解。
我们每次都能从行里面知道:
第一行是只有一个数,是肯定要的于是可以知道dp[1]=a[1][1];
第二次就是因为第二行的数组是3 8 他们能选择最大的左上角和正上方的数字都是7
因此dp[1]=3+7,dp[2]=7+8
第三次就是到了8 1 0,他们每一个数字都可以从左上角和正上方得到一个最大的值与自身相加。
以此类推可以知道:
3.另外我们需要注意的是,dp数组遍历的同时,他在变,所以我们需要先计算完,再给dp数组赋值。
C代码如下:
#include<stdio.h>
#define N 1010
int a[N][N],dp[N],res[N];
int max(int x,int y)
{
if(x>y) return x;
return y;
}
int main()
{
int n,i,j,m;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
}
}
dp[1]=a[1][1];
for(i=2;i<=n;i++)
{
for(j=1;j<=i;j++)
{
res[j]=max(a[i][j]+dp[j],a[i][j]+dp[j-1]);
}
for(j=1;j<=i;j++)
dp[j]=res[j];
}
m=dp[1];
for(i=2;i<=n;i++)
{
// printf("%d ",dp[i]);
if(m<dp[i]) m=dp[i];
}
printf("%d",m);
}
C++代码如下:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N],dp[N],res[N];
int max(int x,int y)
{
if(x>y) return x;
return y;
}
int main()
{
int n,i,j,m;
cin >> n ;
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
cin >> a[i][j] ;
}
}
dp[1]=a[1][1];
for(i=2;i<=n;i++)
{
for(j=1;j<=i;j++)
{
res[j]=max(a[i][j]+dp[j],a[i][j]+dp[j-1]);
}
for(j=1;j<=i;j++)
dp[j]=res[j];
}
m=dp[1];
for(i=2;i<=n;i++)
{
if(m<dp[i]) m=dp[i];
}
cout << m << endl;
}