洛谷[P1216] 数字三角形 Number Triangles

洛谷[P1216] 数字三角形 Number Triangles

题目链接:数字三角形

一、递归
首先最容易想到的肯定是递归。
在这里插入图片描述

#include <iostream>
#include <algorithm>
#define MAX 1001
using namespace std;
int D[MAX][MAX],n;

int MaxSum(int i,int j)
{
    if(i==n)
      return D[i][j];
    int x=MaxSum(i+1,j);
    int y=MaxSum(i+1,j+1);
    return max(x,y)+D[i][j];
}

int main()
{
   int i,j;
   cin>>n;
   for(i=1;i<=n;i++)
      for(j=1;j<=i;j++)
          cin>>D[i][j];
   cout<<MaxSum(1,1)<<endl;
   return 0;
   }

然而这种方法并不可行,对于n(1<=n<=1000),肯定超时。
在这里插入图片描述
此程序中,D[1,1](7)被MaxSum调用1次,D[2,1] (3)和D[2,2] (8)各被调用1次,而D[3,2] (1)被调用2次(D[2,1]和D[2,2]),D[4,2] (7)被D[3,1](8)和D[3,2](1)调用(总计3次)。以此类推,总共调2^0+2^1+2^2+……+2^(n-1)=2^n次。时间复杂度是巨大的,即使到宇宙毁灭也算不出来。

二、记忆递归型动归
在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 1001
int D[MAX][MAX],n;
int maxSum[MAX][MAX];

int MaxSum(int i,int j)
{
   if(maxSum[i][j]!=-1)
      return maxSum[i][j];
   if(i==n) maxSum[i][j]=D[i][j];
   else {
      int x=MaxSum(i+1,j);
      int y=MaxSum(i+1,j+1);
      maxSum[i][j]=max(x,y)+D[i][j];
      }
      return maxSum[i][j];
}

int main()
{
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++)
       for(j=1;j<=i;j++)
       {
          cin>>D[i][j];
          maxSum[i][j]=-1;
       }
       cout<<MaxSum(1,1)<<endl;
       return 0;
 }
   

三、递推型动态规划(典型动态规划)
在这里插入图片描述
从下往上推,二维数组对应位置存储由下往上推到当前位置时更大的那个结果。
在这里插入图片描述
可以看到,对应位置的结果只与上一步推的结果和当前位置的初始值有关。由此可得状态转移方程:maxSum[i][j]=max(maxSum[i+1][j],maxSum[i+1][j+1])+D[i][j]

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 1001
int D[MAX][MAX],n;
int maxSum[MAX][MAX];

int main()
{
   int i,j;
   cin>>n;
   for(i=1;i<=n;i++)
      for(j=1;j<=i;j++)
         cin>>D[i][j];
   for(i=1;i<=n;i++)
      maxsum[n][i]=D[n][i];//底部初始化
   for(i=n-1;i>=1;i--)
      for(j=1;j<=i;j++)
         maxSum[i][j]=max(maxSum[i+1][j],maxSum[i+1][j+1])+D[i][j];
         cout<<maxSum[1][1]<<endl;
         return 0;
 }
   

空间优化(1)
由于二维数组当前行的状态的值确定后,就和下面一行的值无关,因此可以用一维数组存储即可,最后输出maxSum[1]。

在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 1001
int D[MAX][MAX],n,maxSum[MAX];

int main()
{
   int i,j;
   cin>>n;
   for(i=1;i<=n;i++)
      for(j=1;j<=i;j++)
         cin>>D[i][j];
   for(i=1;i<=n;i++)
      maxSum[i]=D[n][i];//底部初始化
   for(i=n-1;i>=1;i--)
      for(j=1;j<=i;j++)
     maxSum[j]=max(maxSum[j],maxSum[j+1])+D[i][j];
   cout<<maxSum[1]<<endl;
   return 0;
 }

空间优化(2)
在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 1001
int D[MAX][MAX],n;
int *maxSum;

int main()
{
   int i,j;
   cin>>n;
   for(i=1;i<=n;i++)
      for(j=1;j<=i;j++)
         cin>>D[i][j];
   for(i=1;i<=n;i++)
      maxSum=D[n];//底部初始化
   for(i=n-1;i>=1;i--)
      for(j=1;j<=i;j++)
     maxSum[j]=max(maxSum[j],maxSum[j+1])+D[i][j];
   cout<<maxSum[1]<<endl;
   return 0;
 }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值