数字三角形问题

来源:互联网 发布:淘宝上的vintage店铺 编辑:程序博客网 时间:2024/05/22 10:25
给定一个由n行数字组成的数字三角形,设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。
(0,0)
(1,0) (1,1)
(2,0) (2,1)(2,2)
(3,0) (3,1)(3,2) (3,3)




思路:动态规划
动态方程: sum(i,j) = a(i,j) + max{sum((i+1),j) , sum((i+1),(j+1))} 。
sum(i,j)表示从(i,j)出发时能得到的最大和(包括(i,j)本身的值),a(i,j)表示位置(i,j)的值。
动态方程可解释为:从(i,j)出发有两种决策。如果往下走,则走到(i+1,j)后需要求“从(i+1,j)出发后所能得到的最大和”这一问题,即sum(i+1,j)。
类似的,往右走之后需要求解sum(i+1,j+1)。由于这两个决策中自由选择,所以应选择d(i+1,j)和d(i+1,j+1)中较大的一个。

原问题的解即为:d(0,0)


#include<stdio.h>int **a;int **sum;int n;//递推计算int func1(int i,int j){int x=i,y=j;//初始化最底层for(j=0;j<n;j++)sum[n-1][j]=a[n-1][j];for(i=n-2;i>=0;i--)//逆序for(j=0;j<=i;j++)if(sum[i+1][j]>=sum[i+1][j+1])sum[i][j] = a[i][j] + sum[i+1][j];elsesum[i][j] = a[i][j] + sum[i+1][j+1];return sum[x][y];}//记忆化搜索,为了避免递归计算的重复计算问题,memset(sum,-1,sizeof(sum))。int func2(int i,int j){//判断是否记忆标记if(sum[i][j]>=0)return sum[i][j];if(i==(n-1))return a[i][j];elseif(func2(i+1,j)>=func2(i+1,j+1))return a[i][j]+func2(i+1,j);elsereturn a[i][j]+func2(i+1,j+1);}int main(){int i,j;scanf("%d",&n);//层数//数组a,d动态申请空间a = new int*[n];for(i=0;i<n;i++)a[i] = new int[n];sum = new int*[n];for(i=0;i<n;i++)sum[i] = new int[n];//键入各点的值for(i=0;i<n;i++)for(j=0;j<=i;j++)scanf("%d",&a[i][j]);//逆推计算printf("%d\n",func1(0,0));//记忆化搜索//将sum初始化为-1,做标记for(i=0;i<n;i++)for(j=0;j<=i;j++)sum[i][j]=-1;printf("%d\n",func2(0,0));return 0;}


0 0