动态规划法是将带求解问题分解成 若干个子问题,若子问题还能分解成多个子问题还需进行分解,最后对所有字问题进行求解。
在数塔问题中,子问题就是求每一层的子塔的最大和,以书上例子为例
顶层为8的5层数塔的子问题是顶层为12的4层数塔和顶层为15的4层数塔,以此类推,顶层为12的4层数塔的子问题是顶层为3的3层数塔和顶层为9的3层数塔以及顶层为6的3层数塔,就按照这个逻辑可以得出数塔的最小子问题是数塔最后一层的值。解决了子问题是为了解决比子问题层次高一点的子问题。例如解决顶层为3的子塔问题是为了解决顶层为12这个子塔的问题,最终求得答案的解。
解决数塔问题,是要求数塔问题的最大和路径和最大和,解决一个问题想到用什么存储方式来存储数据和结果更为合适,这里我用二维数组来存储数塔的所有数据data[][],每一层代表一行,每个数据都在某一行的某一列。因为你要记录每一个节点的最大路径,路径是指向的是一个数,所以最好也用二维数组来表示path[][].
最开始最小子问题中最大和是最后一层的数据,最后一层的每一个节点都是一个子塔,最大和就是他们本身。解决完最后一层的问题然后解决倒数第二层,就拿倒数第二层的8来举例子,解决这个子问题要先比较他的两个子塔的最大和大小,把最大的子塔和和8相加得到最新的maxAdd,至于怎么比较就是data[4][0],data[4][1]相比,8为data[3][0],这里可以发现子塔的列索引是节点的列索引和节点的列索引+1,解决完一个子问题要更新maxAdd和path这里用的C实现的
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,j;
int data[100][100];
int maxAdd[100][100];
int path[100][100];
int n;
printf("请输入数塔的层数 ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)
{
scanf("%d",&data[i][j]);
}
}
for(j=0;j<i;j++)
{
maxAdd[n-1][j]=data[n-1][j];
}
for(i=n-2;i>=0;i--)
{
for(j=0;j<=i;j++)
{
if(maxAdd[i+1][j]>maxAdd[i+1][j+1])
{
maxAdd[i][j]=maxAdd[i+1][j]+data[i][j];
path[i][j]=j;
}
else
{
maxAdd[i][j]=maxAdd[i+1][j+1]+data[i][j];
path[i][j]=j+1;
}
}
}
printf("sum=%d\n",maxAdd[0][0]);
printf("%d",data[0][0]);
j=path[0][0];
for(i=1;i<n;i++)
{
printf("--->%d",data[i][j]);
j=path[i][j];
}
return 0;
}