POJ 1163 The Triangle - 数字三角形详解

本文通过一个具体问题介绍了如何使用递归方法解决问题,并分析其时间复杂度过高的原因。随后引入记忆数组来减少重复计算,最后详细讲解如何将递归转化为动态规划,给出高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意大致:
这里写图片描述
这里写图片描述
这里写图片描述

解题思路:这道题目可以用递归的方法解决。基本思路是:D(r,j)表示第 r 行第 j 个数字(r,j都从 1 开始算),以 MaxSum(r,j)代表从第 r 行的第 j 个数字到底边的最佳路径的数字之和,则本题目要求MaxSum(1,1)。
从某个D(i,j)出发,显然下一步只能走D(r+1,j)或 D(r+1,j+1)。如果走D(r+1,j),那么得到的MaxSum(r,j)就是MaxSum(r+1,j+1)+D(i,j);如果走D(r+1,j+1),那么得到的MaxSum(r,j)就是MaxSum(r+1,j+1)+D(r,j)。所以选择往哪里走就需要比较MaxSum(r+1,j)和MaxSum(r+1,j+1)哪个值更大。

首先我们第一反应有可能是用递归实现上面的思路,但是当你递归程序写出来的时候,你会发现时间复杂度太高了
/*
递归代码:
*/
#include<iostream>
#define MAX 101 
using namespace std;
int D[MAX][MAX];
int n;
int MaxSum(int i,int j){
    if(i == n){
        cout<<"D[i][j]  =   "<<D[i][j]<<endl;
        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); 
    return 0;
} 

我们可以研究一下程序为什么时间复杂度高,我们仔细研究一下程序你会发现其实,这个递归程序里存在着很多重复计算,为了避免重复计算那么我们肯定首先会想到用记忆数组来存储它,每次计算的值,当值被计算过就直接返回值,不再进行更深一层的递归。

记忆数组代码:

#include<iostream>
#define MAX 101 
using namespace std;
int D[MAX][MAX];
int n;
int maxSum[MAX][MAX]; 
int MaxSum(int i,int j){
    if(maxSum[i][j] != -1)
        return maxSum[i][j]; 
    if(i == n){
//      cout<<"D[i][j]  =   "<<D[i][j]<<endl;
        maxSum[i][j] = D[i][j]; 
        return D[i][j];
    }
    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); 
    return 0;
} 

好,下面我们进入我们解这题的正题,其实我前面讲这么多都是为下面我们要讲的动态规划做铺垫
将一个问题分解为子问题递归求解,并且将中间结果保存以避免重复计算的办法,可以称为“动态规划”。动态规划通常用来求最优解。能用动态规划解决的求最优解的问题,必须满足最优解的每个局部解也是最优的。依次以为例,最佳路径中每个数字到底部的那一段路径都是从该数字出发到底部的最佳路径。

下面时把递归转化成递推的的过程
从MaxSum[N-1]行这一行元素开始向上逐行递推,就能求得最终maxSum[1][1]的值
这里写图片描述

/*
动态规划代码
*/
#include<iostream>
using namespace std;
int dp[100][100];
int n; 
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            cin>>dp[i][j];      
        } 
    } 
    for(int i=n;i>=2;i--){
        for(int j=1;j<=i;j++){
            dp[i-1][j] = max(dp[i-1][j]+dp[i][j],dp[i-1][j]+dp[i][j+1]);  
        } 
    } 
    cout<<dp[1][1]<<endl; 
    return 0;   
} 

实际上还可以再进行空间优化….

有什么不懂可以在评论区问我,我会及时回答的,感谢阅读,希望能帮到您!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值