【9901】数塔问题
Time Limit: 10 second
Memory Limit: 2 MB
问题描述
设有一个三角形的数塔,顶点结点称为根结点,每个结点有一个整数数值。从顶点出发,在每一个结点可以选择向左走或者向右走一直走到底层,要求找出一条路径,使路径上的值最大。
Input
第一行有数塔层数n,接下来若干行为数塔。
Output
输出一行数据,即路径的最大值(包括一个换行符)
Sample Input
5 13 11 8 12 7 26 6 14 15 8 12 7 13 24 11
Sample Output
max=86
Sample Input2
10 1 121 18 12 72 26 63 14 15 8 125 57 13 24 11 11 12 63 58 47 45 0 152 365 12 36 59 987 0 1 23 4 5 6 7 8 25 36 99 87 44 51 23 69 65 10 12 35 92 15 2654 21 30 25 69
Sample Output2
max=3401
【题解】
这题是动态规划。先看一下数塔的样子如下
如果只有前两行,我们可以很快的得出来答案是24.
如果又加了一行。则我们不能肯定就是从13->11->12了。
我们在右边也要看一下。因为可能出现一个变态的数字让右边的路径也能更优。
于是我们开一个f[i][j]数组,f[2][1] = 24 f[2][2] = 21;
这样我们就记录了走到第二行第1个数字的最优解,和走到第二行第二个数字的最优解。
然后我们看第三行,可以看到12只能由2,1走到。那么f[3][1] = f[2][1]+a[3][1],a[3][1] = 12;
然后是第三行的第二个数字7,7可以由11 和 8走到,于是我们就判断一下f[2][1]和f[2][3] 它们分别加上a[3][2]后哪一个会比较大。然后把它赋值给f[3][2]。
然后是第三行的第三个数字26,26只能由8走到。于是f[3][3] = f[2][2] + a[3][3];
这样我们就求出了到达第3行第j列的所有位置的最优解。依照我们处理第三行的规律。
我们可以得出第四行的最优解。
由此得出动态转移方程
f[i][j] = max(f[i-1][j-1],f[i-1][j]);
【代码】
#include <cstdio> #include <stdlib.h> int n,a[100][100],f[100][100],ans; void input_data() { scanf("%d",&n); for (int i = 1;i <= n;i++) for (int j = 1;j <=i;j++) //读入数字矩阵 scanf("%d",&a[i][j]); } int ma_x(int x,int y) //获取x和y中的更大值、 { if (x > y) return x; else return y; } void get_ans() { f[1][1] = a[1][1]; //第一排的第一个数字用于作为动规的奠基 for (int i = 2;i <= n;i++) for (int j = 1;j <=i;j++) //然后根据状态转移方程求出下面的f[i][j] f[i][j] = ma_x(f[i-1][j-1]+a[i][j],f[i-1][j]+a[i][j]); ans = f[n][1]; for (int i = 2;i <= n;i++) //在最后一层中找答案(最大值) ans = ma_x(ans,f[n][i]); } void output_ans() { printf("max=%d\n",ans); } int main() { //freopen("F:\\rush.txt","r",stdin); input_data(); get_ans(); output_ans(); return 0; }