题目大意:
- Description
- 下图给出了一个数字三角形,请编写一个程序,计算从顶至底的某处的一条路径,使该路径所经过的数字和最大
- Input
- 有很多个测试案例,对于每一个测试案例, 通过键盘逐行输入,第1行是输入整数(如果该整数是0,就表示结束,不需要再处理),表示三角形行数n,然后是n行数
- Output
- 输出最大值
Example Input
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Example Output
30
解题思路:
这道题如果用枚举法(暴力思想),在层数稍大的情况下(如31),则需要列举出的路径条数将是一个非常庞大的数目(2^30= 1024^3 > 10^9=10亿)。
从顶点出发时到底向左走还是向右走应取决于是从左走能取到最大值还是从右走能取到最大值,只要左右两道路径上的最大值求出来了才能作出决策。 同样,下一层的走向又要取决于再下一层上的最大值是否已经求出才能决策。这样一层一层推下去,直到倒数第二层时就非常明了。 所以实际求解时,可从底层开始,层层递进,最后得到最大值。
结论:自顶向下的分析,自底向上的计算。
#include <cstdio> #include <cstring> /*#define max(a,b) a>b?a:b*/ //这样宏定义max数组会出错,因为下面的状态转移方程中(a>b?a:b)+ans[i][j]会变成(a>b+ans[i][j]?a:b+ans[i][j]) #define max(a,b) ((a)>(b)?(a):(b)) //这样定义才是正确的 int ans[1100][1100], dp[1100][1100]; int main() { int i, j; int n; while (scanf("%d", &n) != EOF) { memset(ans, 0, sizeof(ans)); memset(dp, 0, sizeof(dp)); for (i = 0; i < n; i++) { for (j = 0; j < i+1; j++)scanf("%d", &ans[i][j]); if (i == n - 1) { for (j = 0; j < i+1; j++)dp[i][j] = ans[i][j]; } } for (i = n - 2; i >= 0; i--) { for (j = i; j >= 0; j--) { dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + ans[i][j]; //自底向上构造当前位置的最大路线值 } } //for (i = 0; i < n; i++) //可以查看此时dp数组内的各位数,方便理解 //{ // for (j = 0; j < i + 1; j++)printf("%d ",dp[i][j]); // printf("\n"); //} printf("%d\n", dp[0][0]); } return 0; }
2018-04-27