Standard IO-----数字金字塔(CCF 1145)

来源:互联网 发布:windows专业版和旗舰版 编辑:程序博客网 时间:2024/05/29 03:43

数字金字塔

题目描述
观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到下方的点也可以到达右下方的点。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
在上面的样例中,从7到3到8到7到5的路径产生了最大的和30。

输入
第一个行包含R(1<= R<=1000),表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
所有的被供应的整数是非负的且不大于100。

输出
单独的一行,包含那个可能得到的最大的和。

样例输入

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

样例输出

30

数据范围限制

1<= R<=1000

做题地址:CCF中学生程序设计在线评测系统-1145. 数字金字塔 (需要注册)


这是一道简单经典的DP题目。
如果刚开始入手DP没有思路的话,可以先从搜索的角度想(ˇˍˇ)~


搜索思路
题目要求输出最大和,可以使用深搜把每种情况枚举出来求和,找出最大值。

1<=R<=1000

看这数据范围,TLE,妥妥的。

#include<cstdio>#include<algorithm>using namespace std;int best,a[1005][1005],n;void dfs(int x,int y,int sum){    if(x>n)    {        best=max(best,sum);        return ;    }    dfs(x+1,y,sum+a[x+1][y]);    dfs(x+1,y+1,sum+a[x+1][y+1]);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)        for(int j=1;j<=i;j++)            scanf("%d",&a[i][j]);    dfs(1,1,a[1][1]);    printf("%d\n",best);}/*    Language: C++    Result: 时间超限    Time:2004 ms    Memory:4976 kb*/

既然普通的深搜不行,那试试记忆化搜索吧!把走到当前的最大值记录下来,再遇到时直接比较。
还是TLE……

#include<cstdio>#include<algorithm>#include<iostream>using namespace std;int a[1005][1005],f[1005][1005],ans,n;int F(int x,int y){    if(f[x][y]) return f[x][y];    if(x==1 && y==1) return f[1][1]=a[1][1];    if(x==y) return f[x][y]=a[x][y]+F(x-1,y-1);    if(y==1) return f[x][y]=a[x][y]+F(x-1,y);    return f[x][y]=a[x][y]+max(F(x-1,y-1),F(x-1,y));}int main(){    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++)        ans=max(F(n,i),ans);     printf("%d\n",ans);}/*    Language: C++    Result: 时间超限    Time:1998 ms    Memory:9392 kb*/

唉╮(╯▽╰)╭


DP隆重登场

DP中有两个很重要的概念:

状态——对于一个多阶段问题,描述在一系列阶段后所处的一个状况

转移——将复杂状态转为简单状态

知道了这些,就可以愉快的码DP了

~\(≧▽≦)/~


DP代码

#include<cstdio>#include<algorithm>#include<iostream>using namespace std;int a[1005][1005],f[1005][1005],ans,n;void F(){    for(int i=2;i<=n;i++)        for(int j=1;j<=i;j++)        {            if(j==1)                f[i][j]=f[i-1][j]+a[i][j];            else                if(j==i)                    f[i][j]=a[i][j]+f[i-1][j-1];                else                    f[i][j]=max(f[i-1][j-1],f[i-1][j])+a[i][j];        }}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)        for(int j=1;j<=i;j++)            scanf("%d",&a[i][j]);    f[1][1]=a[1][1];    F();    for(int i=1;i<=n;i++)        ans=max(f[n][i],ans);     printf("%d\n",ans);}/*    Language: C++    Result: 正确    Time:95 ms    Memory:9392 kb*/

IN THE END

上面两段TLE代码,除了凑字数(凑字咋地),还有重要的一点:
使用搜索的思路看DP题可以避免千篇一律的套公式。