Description
7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 (Figure 1)
Input
Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 99.
Output
Your program is to write to standard output. The highest sum is written as an integer.
Sample Input
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
Sample Output
30
题目大意:求出三角形的最大和,规定路径从第一行第一个为起点,路径为向下一行的该列或者下一行的右边的一列(在所有数字向左对齐的情况下),终点为最后一行的某个数。
解题思路:这是一道dp教程中十分常见的入门题,在解这道题目我们要尽量防止回溯,因为很有可能会超时(实际上也超了),所以我们十分需要用一个数组来储存过程中计算得到的结果,在代码里面我定义为dp数组,dp[i][j]表示从倒数第一排开始走到i排j列的最大和,如果输入是样例输入的话,那么dp数组应该是这样的。
30 23 21 20 13 10 7 12 10 10 4 5 2 6 5
(其余为0)
递归代码
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define MAXN 100 using namespace std; int map[MAXN + 5][MAXN + 5]; int dp[MAXN + 5][MAXN + 6]; int n; int sum; int maxsum(int x, int y) { if(dp[x][y] != -1)//dp[x][y]!=-1表示已经计算了,不必再算 return dp[x][y]; if(x == n)//x==n表示最后一行,最小和为map[x][y]他本身 { dp[x][y] = map[x][y]; } else { int i = maxsum(x + 1, y); int j = maxsum(x + 1, y + 1); dp[x][y] = max(i, j) + map[x][y]; } return dp[x][y]; } int main() { cin >> n; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= i; j ++) { scanf("%d", &map[i][j]); dp[i][j] = -1; } } cout << maxsum(1, 1) << endl; for(int i = 1; i <= n; i++) { for(int j = 1; j <= i; j ++) { cout << dp[i][j] << ' '; } cout << endl; } return 0; } /* 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 ans:30 */
递推代码
递推代码的空间优化:#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define MAXN 100 using namespace std; int map[MAXN + 5][MAXN + 5]; int dp[MAXN + 5][MAXN + 6]; int n; int sum; int main() { cin >> n; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= i; j ++) { scanf("%d", &map[i][j]); } } for(int i = 1; i <= n; i ++)//最后一行的最大和是最后一行的数字本身 dp[n][i] = map[n][i]; for(int i = n - 1; i >= 1; i --)//从最后一排到第一排 { for(int j = 1; j <= i; j ++) { dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + map[i][j]; } } cout << dp[1][1] << endl; return 0; } /* 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 ans:30 */
空间优化的思路:将dp从二维转换为一维很明显能节省很多空间,dp[i]这时候表示第一行i列为终点的最大和
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define MAXN 100 using namespace std; int map[MAXN + 5][MAXN + 5]; int dp[MAXN + 5]; int n; int sum; int main() { cin >> n; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= i; j ++) { scanf("%d", &map[i][j]); } } for(int i = 1; i <= n; i ++)//最后一行的最大和是最后一行的数字本身 { dp[i] = map[n][i]; } for(int i = n - 1; i >= 1; i --)//从最后一排到第一排 { for(int j = 1; j <= i; j ++) { dp[j] = max(dp[j], dp[j + 1]) + map[i][j]; } } cout << dp[1] << endl; return 0; } /* 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 ans:30 */