数塔问题
1.onlineJ43:数塔问题
有一个由数字组成的三角形数塔,站在上一层的某个点,只能到达其下方左右的两个点。现在请找到一条从上到下的路径,使得路径上所有数字相加之和最大
1.递推法从上向下求和
由数塔中到达任意一点的数字和sum = 左上方数字和suml or 右上方数字和sumr + 该数字数值num
知到达该点最大和为ans[x][y] = max(ans[x - 1][y - 1], ans[x - 1][y]) + num[x][y]
==关键==
遍历最后一行,找出最大的数字即为结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <iostream> #include <cstdio> using namespace std;int n;int num[1005 ][1005 ];int main () { scanf ("%d" , &n); for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= i; ++j){ scanf ("%d" , &num[i][j]); } } for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= i; ++j){ num[i][j] += max (num[i - 1 ][j - 1 ], num[i - 1 ][j]); } } int ans = 0 ; for (int i = 1 ; i <= n; ++i){ ans = max (ans, num[n][i]); } printf ("%d\n" , ans); return 0 ; }
2.递推法从下向上求和
由数塔中到达任意一点的数字和sum = 左下方数字和suml or 右下方数字和sumr + 该数字数值num,
知到达该点最大和为num[x][y] = max(num[x + 1][y], num[x + 1][y + 1]) + num[x][y]
==关键==
对整个数塔处理后,最大值即为(1, 1)点处的数值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <cstdio> using namespace std;int n, num[1005 ][1005 ];int main () { scanf ("%d" , &n); for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= i; ++j){ scanf ("%d" , &num[i][j]); } } for (int i = n; i > 0 ; --i){ for (int j = 1 ; j <= i; ++j){ num[i][j] += max (num[i + 1 ][j], num[i + 1 ][j + 1 ]); } } printf ("%d\n" , num[1 ][1 ]); return 0 ; }
如下图是一个数塔,映射到该数塔上行走的规则为:从左上角的点开始,向下走或向右下走直到最底层结束。
1 2 3 4 5 1 3 8 2 5 0 1 4 3 8 1 4 2 5 0
路径最大和是 1+8+5+4+4=221+8+5+4+4=22,1+8+5+3+5=221+8+5+3+5=22 或者 1+8+0+8+5=221+8+0+8+5=22
小 S 觉得这个问题 so easy,于是他提高了点难度,他每次 ban 掉一个点,然后询问你不走该点的最大路径和。当然他上一个询问被 ban 掉的点过一个询问就会恢复。
如果被 ban 掉后不存在任意一条路径,则输出 −1。
1.利用最大值、次大值输出预处理答案
利用数塔问题的两种解法,从上向下和、从下向上和可以求出经过某点(x, y)最大数字和数组
找到每一行的最大值(记录下标)、次大值(记录数值)
对于某一次询问(x, y),判断被ban的值是否为最大值;如果不是输出最大值,否则直接输出次大值
总述:将数塔输入并存储在二维数组中,利用数塔问题的两种解法将绿色、蓝色二维数组求出
求出黑色二维数组(经过某点所能获得的最大和),最后通过记录最大值、次大值来求出结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <iostream> #include <cstdio> using namespace std;int n, m, num[1005 ][1005 ], utd[1005 ][1005 ], dtu[1005 ][1005 ], ans[1005 ][1005 ];int mmax[1005 ], mmax_ind[1005 ], mmax2[1005 ];int main () { scanf ("%d%d" , &n, &m); for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= i; ++j){ scanf ("%d" , &num[i][j]); } } for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= i; ++j){ utd[i][j] = max (utd[i - 1 ][j - 1 ], utd[i - 1 ][j]) + num[i][j]; } } for (int i = n; i > 0 ; --i){ for (int j = 1 ; j <= i; ++j){ dtu[i][j] = max (dtu[i + 1 ][j], dtu[i + 1 ][j + 1 ]) + num[i][j]; } } for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= i; ++j){ ans[i][j] = utd[i][j] + dtu[i][j] - num[i][j]; } } for (int i = 2 ; i <= n; ++i){ int m = 0 , m2 = 0 , ind = 0 ; for (int j = 1 ; j <= i; ++j){ if (m < ans[i][j]){ m2 = m; m = ans[i][j]; ind = j; }else if (m2 < ans[i][j]){ m2 = ans[i][j]; } } mmax[i] = m, mmax_ind[i] = ind, mmax2[i] = m2; } for (int i = 0 ; i < m; ++i){ int x, y; scanf ("%d%d" , &x, &y); if (x == 1 ){ printf ("-1\n" ); }else if (mmax_ind[x] == y){ printf ("%d\n" , mmax2[x]); }else { printf ("%d\n" , mmax[x]); } } return 0 ; }