题目:
给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形
的顶至底的一条路径,使该路径经过的数字总和最大。(只能走正下 和 右下)
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
编程任务:
对于给定的由n 行数字组成的数字三角形,编程计算从三角形的顶至底的路径经过的数
字和的最大值。
解法一,普通递归:
用二维数组存放数字三角形。
D ( r , j ):第所亍第 j 个数字( r , j 从1开始算)
MaxSum ( r , j ):从 D ( r , j )到底边的各条路径中,最佳路径的数字之和。 问题:求 MaxSum (1,1)典型的递归问题。
有大量的重复计算,时间复杂度太高。``
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n;
int Maxsum(int i, int j)
{
if(i==n){
return D[i][j];
}
int x = Maxsum(i+1, j);
int y = Maxsum(i+1, j+1);
return max(x, y) + D[i][j];
}
int main()
{
int i, j;
cin >> n;
for(i=1; i<=n; i++){
for(j=1; j<=i; j++){
cin >> D[i][j];
}
}
cout << Maxsum(1, 1) << endl;
return 0;
}
解法二,记忆型递归:
改进
如果每算出一个 MaxSum ( rj )就保存起来,下次用到其值的时候直接取用,则可免去重复计算。
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int maxsum[MAX][MAX];
int n;
int Maxsum(int i, int j)
{
if(maxsum[i][j] != -1){ //避免重复计算
return maxsum[i][j];
}
if(i==n){
maxsum[i][j] = D[i][j];
}else{
int x = Maxsum(i+1, j);
int y = Maxsum(i+1, j+1);
maxsum[i][j] = max(x, y)+D[i][j];
}
return maxsum[i][j];
}
int main()
{
int i, j;
cin >> n;
for(i=1; i<=n; i++){
for(j=1; j<=i; j++){
cin >> D[i][j];
maxsum[i][j] = -1;
}
}
cout << Maxsum(1, 1) << endl;
return 0;
}
解法三,动态规划:
递归转成递推,先从底部的数字开始,从下到上。
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int maxsum[MAX][MAX];
int n;
int main()
{
int i, j;
cin >> n;
for(i=1; i<=n; i++){
for(j=1; j<=i; j++){
cin >> D[i][j];
}
}
for(int i=1; i<=n; i++){
maxsum[n][i]=D[n][i];
}
for(int i=n-1; i>=1; --i){
for(int j=1; j<=i; ++j){
maxsum[i][j]=max(maxsum[i+1][j], maxsum[i+1][j+1]) + D[i][j];
}
}
cout << maxsum[1][1] << endl;
return 0;
}
还可以进行空间优化,不用二维 maxSum 数组存储每一个数,只要从底层一行行向上递推,那么只要一维数组 maxSum [100]即可,即只要存储一行的 MaxSum 值就可以。