问题描述
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
- 在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。只需要求出这个最大和即可,不必给出具体路径。
- 三角形的行数大于1小于等于100,数字为0-99
解题思路
- 用二维数组存放数字三角形。
- D(r,j):第r行第j个数字(r,j从1开始算)
- MaxSum(r,j):从D(r,j)到底边的各条路径中,最佳路径的数字之和。
- 问题:求MaxSum(1,1)
- 典型的递归问题:D(r,j)出发,下一步只能走D(r+1,j+1)。故对于N行的三角形:
if ( r == N )
MaxSum(r,j) = D(r,j);
else
MaxSum(r,j) = Max{ MaxSum(r+1,j), MaxSum(r+1, j+1) } + D(r, j);
整体代码如下:
#include<stdio.h>
#define MAX 101
int D[MAX][MAX];
int n;
int max(int a, int b)
{
if(a-b >= 0)
return a;
else
return b;
}
int MaxSum(int i, int j)
{
int x, y;
if(i == n)
return D[i][j];
x = MaxSum(i+1, j);
y = MaxSum(i+1, j+1);
return max(x, y) + D[i][j];
}
int main()
{
int i, j;
scanf("%d", &n);
for(i = 1; i <= n; i++)
for(j = 1; j <= i; j++)
scanf("%d", &D[i][j]);
printf("The MaxSum is %d\n", MaxSum(1, 1));
return 0;
}
- 上述代码采用递归的方法,深度遍历每一条路径,存在大量重复计算。则时间复杂度为 2 n 2^n 2n,对于n = 100行,肯定超时。
改进
- 如果每次算出一个MaxSum(r,j)就保存起来,下次用到其值的时候直接取用,则可以免去重复计算。那么可以用 O ( n 2 ) \Omicron(n^2) O(n2)时间完成计算。因为三角形的数字总数时n(n+1)/2
- 改进代码如下:
#include<stdio.h>
#define MAX 101
int D[MAX][MAX];
int maxSum[MAX][MAX];
int n;
int max(int a, int b)
{
if(a-b >= 0)
return a;
else
return b;
}
int MaxSum(int i, int j)
{
int x, y;
if(maxSum[i][j] != -1)
return maxSum[i][j];
if(i == n)
maxSum[i][j] = D[i][j];
x = MaxSum(i+1, j);
y = MaxSum(i+1, j+1);
maxSum[i][j] = max(x, y) + D[i][j];
return maxSum[i][j];
}
int main()
{
int i, j;
scanf("%d", &n);
for(i = 1; i <= n; i++)
for(j = 1; j <= i; j++)
{
scanf("%d", &D[i][j]);
maxSum[i][j] = -1;
}
printf("The MaxSum is %d\n", MaxSum(1, 1));
return 0;
}
示意图
![](https://i-blog.csdnimg.cn/blog_migrate/66cfe5c4d26da0f029159adc8cc6be46.png)
空间优化
- 没必要使用二维maxSum数组存储每一个MaxSum(r,j),只要从底层一行向上递推,那么只要一维数组maxSum[100]即可,即只要存储一行的MaxSum值就可以。
- 进一步考虑,连maxSum数组都可以不要,直接用D的第n行替代maxSum即可。
- 节省空间,时间复杂度不变。
改进代码如下:
#include<stdio.h>
#define MAX 101
int D[MAX][MAX];
int *maxSum;
int n;
int max(int a, int b)
{
if(a-b >= 0)
return a;
else
return b;
}
int main()
{
int i, j;
scanf("%d", &n);
for(i = 1; i <= n; i++)
for(j = 1; j <= i; j++)
scanf("%d", &D[i][j]);
maxSum = D[n];
for(i = n-1; i >= 1; i--)
for(j = 1; j <= i; j++)
maxSum[j] = max(maxSum[j], maxSum[j+1]) + D[i][j];
printf("The MaxSum is %d\n", maxSum[1]);
return 0;
}
注:文中问题及代码参考 MOOC——《程序设计与算法》(北京大学 郭炜)