2、法解决。基本思路是:以D(r,j)表示第r行第j个数字(r,j都从1开始算),以MaxSum(r,j)代表从第r行的第j个数字到底边的最佳路径的数字之和,则本题是要求MaxSum(1,1)。从某个D(r,j)出发,显然下一步只能走D(r+1,j)或者D(r+1,j+1)。如果走D(r+1,j),那么得到的MaxSum(r,j)就是MaxSum(r+1,j)+D(r,j);如果走D(r+1,j+1),那么得到的MaxSum(r,j)就是MaxSum(r+1,j+1)+D(r,j)。所以,选择往哪里走,就看MaxSum(r+1,j)和MaxSum(r+1,j+1)哪个更大了。3、参考程序I#
3、include#defineMAX_NUM100intD[MAX_NUM+10][MAX_NUM+10];intN;intMaxSum(intr,intj){if(r==N)returnD[r][j];intnSum1=MaxSum(r+1,j);intnSum2=MaxSum(r+1,j+1);if(nSum1>nSum2)returnnSum1+D[r][j];returnnSum2+D[r][j];}3、参考程序Iintmain(void){intm;scanf("%d",&N);for(inti=1;i<=N;i++)for(intj=1;j<=i;j++)sc
4、anf("%d",&D[i][j]);printf("%d",MaxSum(1,1));return0;}提交结果:TimeLimitExceed程序I分析上面的程序,效率非常低,在N值并不大,比如N=100的时候,就慢得几乎永远算不出结果了。为什么会这样呢?是因为过多的重复计算。我们不妨将对MaxSum函数的一次调用称为一次计算。那么,每次计算MaxSum(r,j)的时候,都要计算一次MaxSum(r+1,j+1),而每次计算MaxSum(r,j+1)的时候,也要计算一次MaxSum(r+1,j+1)。重复计算因此产生。在题目中给出的例子里,如果我们将MaxSum(r,j)被计算的次数
5、都写在位置(r,j),那么就能得到右面的三角形:111121133114641738810274445265程序分析从上图可以看出,最后一行的计算次数总和是16,倒数第二行的计算次数总和是8。不难总结出规律,对于N行的三角形,总的计算次数是2^0+2^1+2^2+…+2^(N-1)=2^N-1。当N=100时,总的计算次数是一个让人无法接受的大数字。既然问题出在重复计算,那么解决的办法,当然就是,一个值一旦算出来,就要记住,以后不必重新计算。即第一次算出MaxSum(r,j)的值时,就将该值存放起来,下次再需要计算MaxSum(r,j)时,直接取用存好的值即可,不必再次调用MaxSum进
6、行函数递归计算了。这样,每个MaxSum(r,j)都只需要计算1次即可,那么总的计算次数(即调用MaxSum函数的次数)就是三角形中的数字总数,即1+2+3+…+N=N(N+1)/2。如何存放计算出来的MaxSum(r,j)值呢?显然,用一个二维数组aMaxSum[N][N]就能解决。aMaxSum[r][j]就存放MaxSum(r,j)的计算结果。下次再需要MaxSum(r,j)的值时,不必再调用MaxSum函数,只需直接取aMaxSum[r][j]的值即可。4、参考程序II#include#include#defineMAX_NUM100intD
7、[MAX_NUM+10][MAX_NUM+10];intN;intaMaxSum[MAX_NUM+10][MAX_NUM+10];intMaxSum(intr,intj){if(r==N)returnD[r][j];if(aMaxSum[r+1][j]==-1)//如果MaxSum(r+1,j)没有计算过aMaxSum[r+1][j]=MaxSum(r+1,j);if(aMaxSum[r+1][j+1]==-1)aMaxSum[r+