Description
观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。
在上面的样例中,从 13 到 8 到 26 到 15 到 24 的路径产生了最大的和 86。
Format
Input
第一个行包含 R(1≤R≤1000),表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
所有的被供应的整数是非负的且不大于100。
Output
单独的一行,包含那个可能得到的最大的和。
Samples
Sample Input 1
5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11
Sample Output 1
86
Solution
在这题中我们需要求金字塔的最长路径,要求全局最优解,所以这一题要用DP。
知道用DP,那就需要求解动态转移方程。
我们仔细观察,发现:
1,能到达 tower[i][j](j ≠ 1且j ≠ i),只有tower[i-1][j-1] 与 tower[i-1][j]。我们以下面一图中12、7、14作为例子。(画的图不太好,见谅)
其中 14 所在的位置是 tower[4][2],我们发现只有12和7能下一层选择14,12所在的位置是 tower[3][1],7所在的位置是 tower[3][2]。
2,能到达 tower[i][j](j = 1),仅有上一层金字塔的第一个元素,也就是 tower[i-1][j](j = 1)。我们以6,12作为例子。
其中12所在的位置是 tower[5][1],我们发现只有 6 能下一层选12,6所在的位置是 tower[4][1] 。
3,能到达 tower[i][j](j = i),仅有上一层金字塔的最后个元素,也就是 tower[i-1][j-1](j = i)。我们以13,8作为例子。
其中8所在的位置是 tower[2][2],我们发现只有 13 能下一层选8,13所在的位置是 tower[1][1] 。
综上所述,我们就可以得到动态转移方程:
(因为我们要求最大值,所以当进行到第 i 行的两个数值较小的数值可以舍弃)
Code
#include <bits/stdc++.h>
using namespace std;
const int MAX_R = 1001;
int R, tower[MAX_R][MAX_R], dp[MAX_R][MAX_R];
int main(){
scanf("%d", &R);
for(int i = 1;i <= R; i++) //输入
for(int j = 1;j <= i; j++)
scanf("%d", &tower[i][j]);
dp[1][1] = tower[1][1]; //第1行1列为起始点,dp数组就为本身的值
for(int i = 2;i <= R; i++)
for(int j = 1;j <= i; j++){ //详见solution
if(j == 1)
dp[i][j] = tower[i][j] + dp[i - 1][j];
else if(j == i)
dp[i][j] = tower[i][j] + dp[i - 1][j - 1];
else
dp[i][j] = tower[i][j] + max(dp[i - 1][j - 1], dp[i - 1][j]);
}
int res = -1;
for(int j = 1;j <= R; j++) //比较进行求出最下面一行数值的最大值,就为本题所求
res = max(res, dp[R][j]);
printf("%d", res);
return 0;
}