Description
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
在上面的样例中,从7→3→8→7→5 的路径产生了最大权值。
Input
第一个行一个正整数 r ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
Output
单独的一行,包含那个可能得到的最大的和。
Sample 1
Inputcopy | Outputcopy |
---|---|
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 | 30 |
Hint
【数据范围】
对于 100%100% 的数据,1≤r≤1000,所有输入在 [0,100][0,100] 范围内。
思路
题目要求从最高点到最低点的路径中权值最大的一条路径
我们既可以从上到下考虑,也可以从下到上考虑
如果从上到下考虑的话,要考虑是从左上下来还是右上下来,这时最右边的数据要进行特判,因为它没有右上数,所以我们从下到上考虑。
我们用二维数组来存储数据,则最大路径中(i,j)这个数由(i+1,j)或(i+1,j+1)中最大的那个相连,而这两个点又由它们下面最大的相连,也就是递归来求,设f(i,j)表示从底层到这个点的最大路径的和;w(i,j)表示这个点的数,那么f(i,j) = (i+1,j)和(i+1,j+1)中路径和大的那个 + w(i,j)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;//大于1000即可
int f[N][N];//从最下方走到(i,j)的所有路线里的最大值
int w[N][N];//第i行第j列的数
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= i;j++)
{
cin >> w[i][j];//输入三角形矩阵
}
}
//初始化最下面一行
for(int i = 1;i <= n;i++)
{
f[n][i] = w[n][i];
}
//求最大路径和
for(int i = n-1;i > 0;i--)
{
for(int j = 1;j <= i;j++)
{
//第i行第j个的数的最大值就等于 从它左下和右下来的数据中的最大值加它本身
f[i][j] = max(f[i+1][j],f[i+1][j+1]) + w[i][j];
}
}
//从最下方走到(1,1)的所有路径的最大值
cout << f[1][1] <<endl;
return 0;
}
详细讲解:【寒假每日一题】Day-2(《898. 数字三角形》动态规划)_哔哩哔哩_bilibili
解法二:dp
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int g[N][N];//存数
int f[N][N];//用f来表示状态
int r;
int main()
{
cin >> r;
//读入三角形
for(int i = 1;i <= r;i++)
{
for(int j = 1;j <= i;j++)
{
cin >> g[i][j];
}
}
//将三角形及周边点初始化为负无穷
for(int i = 0;i <= r+1;i++)
{
for(int j = 0;j <= r+1;j++)
{
f[i][j] = -0x3f;
}
}
//dp核心
//每个点由它左上或右上来,左上即[i-1][j-1],右上即f[i-1][j],再加上它本身,两个中最大的就是最大值
f[1][1] = g[1][1];
for(int i = 2;i <= r;i++)
{
for(int j = 1;j <= r;j++)
{
f[i][j] = max(f[i-1][j-1]+g[i][j],f[i-1][j]+g[i][j]);
}
}
//计算最后一行中最大的值
int res = 0;
for(int i = 1;i <= r;i++)
{
res = max(res,f[r][i]);
}
cout << res <<endl;
return 0;
}