9.1数字三角形(记忆化搜索与递推)

来源:互联网 发布:怎么联系淘宝店铺客服 编辑:程序博客网 时间:2024/05/16 23:59

dp是递推
记忆化搜索是递归+“备忘录”
两者原理是一样的,时间复杂度上也是一样的。可以在熟练记忆化搜索后找出递推关系式。

数字三角形问题。 有一个由非负整数组成的三角形,第一行只有一个数,除了最下行之外每个数的左下方和右下方各有一个数。从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数全部加起来。如何走才能使得这个和尽量大?
1
3 2
4 10 1
4 3 2 20

(结果是24)

记忆化搜索

//首先贴上讲解dp的一篇文章http://www.cnblogs.com/SDJL/archive/2008/08/22/1274312.html#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int dp[100][100],a[100][100],n;int solve(int i,int j)//递归加上一个备忘录就是记忆化搜索保证每个结点只访问一次 {    if(dp[i][j]>=0) return dp[i][j];//dp也就是上文中的备忘录     if(i==n+1) return 0;//想想为什么是n+1(最后一行<第n行>之后没有数了所以是0这句话也就是判断是否到达了边界)     return dp[i][j]=a[i][j]+max(solve(i+1,j),solve(i+1,j+1));//C语言有"赋值语句本身有返回值"的规定,可以把保存dp[i][j]的工作合并到函数的返回语句中 }int main(){    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                scanf("%d",&a[i][j]);        /*for(int i=1;i<=n;i++)        {            for(int j=1;j<=i;j++)            {                printf("%d,%d===%d *",i,j,a[i][j]);            }            printf("\n");        }*/         memset(dp,-1,sizeof(dp));        printf("%d\n",solve(1,1));    }    return 0;}/*IN41 3 2 4 10 1 4 3 2 20OUT24 */

递推:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int dp[110][110],a[110][110],n;int solve()//递推的关键是边界和计算顺序 {    for(int j=1;j<=n;j++) dp[n][j]=a[n][j];    for(int i=n-1;i>=1;i--)//从后往前推         for(int j=1;j<=i;j++)//对行遍历             dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);}int main(){    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                scanf("%d",&a[i][j]);        /*for(int i=1;i<=n;i++)        {            for(int j=1;j<=i;j++)            {                printf("%d,%d===%d *",i,j,a[i][j]);            }            printf("\n");        }*/         //memset(dp,-1,sizeof(dp));        solve();         printf("%d\n",dp[1][1]);    }    return 0;}

递推改进版:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int dp[110][110],a[110][110],n;void solve(){    //for(int j=1;j<=n;j++) dp[n][j]=a[n][j];    for(int i=n;i>=1;i--)        for(int j=1;j<=i;j++)            dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);}int main(){    while(~scanf("%d",&n))    {        memset(a,0,sizeof(a));        memset(dp,0,sizeof(dp));        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                scanf("%d",&a[i][j]);        solve();        printf("%d\n",dp[1][1]);    }    return 0;}