问题描述:
有一个形式如下的数字三角形:
7
3 8
8 1 0
2 7 7 4
4 5 2 6 5
从三角形顶点,沿左斜线方向或右斜线方向下降到三角形底边的路线是一条合法路径。
例如,图中用红色标出的路径就是合法的;我们可以将这条路径记为“LLRL”,它经过了7,3,8,7,5这5个数字,它们的和是30。
请编写一个程序,求解一条合法路径,使这条路径上经过的各数字的总和最大,并把这个最大的总和以及你的路径输出出来。如果路径不止一条,则优先选择向左走。
分析:
问题可以看成如下:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
#include <iostream.h>
#include <memory.h>
#define Max 1001
int N; //N为数字三角形的行数,定义为全局变量,减少调用函数的参数,
int Num[Max][Max]; //各位置的数字
int Record_Num[Max][Max]; //记录数字的变化
int Num_Triangle(int m,int n) //m表示行,n表示在m行的第n个数
{
if(m==N)
{
return Num[m][n];
}
if(Record_Num[m+1][n]==-1) //表示Record_Num[m+1][n]未计算过
Record_Num[m+1][n]=Num_Triangle(m+1,n);
if(Record_Num[m+1][n+1]==-1)
Record_Num[m+1][n+1]=Num_Triangle(m+1,n+1);
if(Record_Num[m+1][n]>Record_Num[m+1][n+1])
return Record_Num[m+1][n]+Num[m][n];
else return Record_Num[m+1][n+1]+Num[m][n];
}
void path() //打印路径。思路是经过一轮数字三角形的扫描,
{ //数组Record_Num中各元素记录了从下往上走的最大路径之和,如Record_Num[2][1]表示结点Num[2][1]到三角形的底的路径之和
int i,j;
cout<<Num[1][1]<<" "; //打印第一个数字,即起点
for(i=1,j=1;i<N;)
{
if(Record_Num[i+1][j]>Record_Num[i+1][j+1]) //对比左右路径,谁大就打印相对应的结点,就走那边
{
cout<<Num[i+1][j]<<" ";
i++;
}
else
{
cout<<Num[i+1][j+1]<<" ";
i++;
j++;
}
}
cout<<endl;
}
void main()
{
cout<<"请先输入三角形的行数,换行(Enter键换行)后开始构造三角形:";cin>>N;
memset(Record_Num,-1,sizeof(Record_Num)); //让数组Record_Num中的所有元素置为1;
for(int i=1;i<=N;i++)
for(int j=1;j<=i;j++)
cin>>Num[i][j];
cout<<"最大的路径总和为:"<<Num_Triangle(1,1)<<" "<<"该路径为:";
path(); //打印路径,注意需要在Num_Triangle()调用之后才能用
}