题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
在上面的样例中,从 7→3→8→7→57→3→8→7→5 的路径产生了最大权值。
输入格式
第一个行一个正整数 𝑟r ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
输出格式
单独的一行,包含那个可能得到的最大的和。
输入输出样例
输入
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 输出 30
说明/提示
【数据范围】
对于 100%的数据,1≤𝑟≤10001≤r≤1000,所有输入在 [0,100] 范围内。
题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
啊啊啊,好麻烦怎么写,完了又不会了,那么多步怎么走,别急,让爱因斯坦.中国分坦来解释一下。不就是从上往下走,然后看哪条路权重最大嘛。先用一个二维数组给数据存起来
咱们来看这个1,怎么走最近,肉眼很容易看出来7->8->1呗,so so easy ,那是不是从第二层最大的往下挑选一个再往下加,这不就是把整体问题转化成局部问题的典型DP问题嘛。我们看走到第四层的7怎么走。到7只有8或者1可以到,所以我们就要比较两者从开始第一层到自己权重谁的大,再决定用它们两个其中的谁来到达7,DP秒了秒了。不就是dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j]。状态转化方程都已经搞出来了,那不就迎刃而解了。把到每一步的最大值都求出来,然后遍历最后一组找出最大值输出就过了!
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2005;
int a[N][N],dp[N][N];
signed main ()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n;cin>>n;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=i;j++)
cin>>a[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=i;j++)
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j];
}
}
int ma=INT_MIN;
for (int i=1;i<=n;i++)
{
if (ma<dp[n][i])
{
ma=dp[n][i];
}
}
cout<<ma;
}