数字三角形

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

    在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。
路径上的每一步都只能往左下或右下走。只需要求出这个最大和即可,不必给出具体路径
    三角形的行数大于1小于等于100,数字为 0 - 99

输入格式:
5//三角形行数
7
3   8
8   1   0
2   7   4   4
4   5   2   6   5
要求输出最大和

解题思路一:
用二维数组存放数字三角形。
D(r,j):第r行第j个数字(r,j从1开始算)
MaxSum(r,j):从D(r,j)到底边的各路径中,最佳路径的数字之和。
问题:求MaxSum(1,1)

典型的递归问题
D(r,j)出发,下一步只能走D(r+1,j)或D(r+1,j+1)。
故对于N行的三角形:
if(r==N){
    MaxSum(r,j)=D(r,j);
}else{
    MaxSum(r,j)=Max{MaxSum(r+1,j),MaxSum(r+1,j+1)}+D(r,j);
}

/**
 * 数字三角形问题
 * 解法一:递归法
 */
#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int n;
//MaxSum(r,j)代表D(r,j)到底部的最大数字和
int MaxSum(int r,int j){
    if(r==n){
        return D[r][j];
    }else{
        return max(MaxSum(r+1,j),MaxSum(r+1,j+1))+D[r][j];
    }
}

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

 

超时!!!

重复计算!!!
                7(1)
            3(1)    8(1)
        8(1)    1(2)    0(1)
    2(1)    7(3)    4(3)    4(1)
4(1)    5(4)    2(6)    6(4)    5(1)
如果采用递归的方法,深度遍历每条路径,存在大量重复计算。
则时间复杂度为2^n,对于n=100行,肯定超时。

改进

如果每算出一个MaxSum(r.j)就保存起来,下次用到其值的时候直接取用,
则可免去重复计算。那么可以用O(n^2)时间完成计算。因为三角形的数字总是n(n+1)/2

/**
 * 数字三角形的记忆递归型动归程序
 * 解法二:递归记忆法
 */
#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int maxSum[MAX][MAX];
int n;
//MaxSum(r,j)代表D(r,j)到底部的最大数字和
int MaxSum(int r,int j){
    if(maxSum[r][j]!=-1)
        return maxSum[r][j];
    if(r==n){
       maxSum[r][j] = D[r][j];
    }else{
        maxSum[r][j]=max(MaxSum(r+1,j),MaxSum(r+1,j+1))+D[r][j];
    }
    return maxSum[r][j];
}

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

 

 

递归转成递推
7                           30
3   8                       23  21
8   1   0                   20  13  10
2   7   4   4               7   12  10  10
4   5   2   6   5           4   5   2   6   5

/**
 * 解法三:递归转递推
 */
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int MaxSum[MAX][MAX];
int D[MAX][MAX];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            cin>>D[i][j];
        }
    }
    //最底层
    for(int i=1;i<=n;i++){
        MaxSum[n][i]=D[n][i];
    }
    //逐层往上递推
    for(int i=n-1;i>=1;i--){
        for(int 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];

    return 0;
}

 

空间优化
7                           7   21  10  10  5
3   8                       23  21  10  10  5
8   1   0                   20  13  10  10  5
2   7   4   4               7   12  10  10  5
4   5   2   6   5           4   5   2   6   5

没必要用二维数组maxSum数组存储每一个MaxSum(r,j),只要从底层一行行向上递推,
那么只要一维数组maxSum[100]即可,即只要存储一行的MaxSum的值就可以。

/**
 * 解法四:空间优化
 * 二维辅助数组转一维辅助数组
 */
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 101;
int D[MAX][MAX];
int *maxSum;

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

进一步考虑,连maxSum数组都可以不要,直接用D的第n行代替maxSum即可。
节省空间,时间复杂度不变。

/**
 * 解法五:空间优化二
 * 不使用辅助数组
 */
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 101;
int D[MAX][MAX];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            cin >> D[i][j];
        }
    }
   
    for (int i = n - 1; i >= 1; i--)
    {
        for (int j = 1; j <= i; j++)
        {
           D[i][j] = max(D[i+1][j], D[i+1][j + 1]) + D[i][j];
        }
    }
    cout << D[1][1];
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值