动态规划之数字三角形

            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;
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;
}

但是,上述的递归方法时间复杂度太大,为2的n次方,不可取。
因此,选择记忆递归型动归程序,其时间复杂度为n的2次方。

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

将动归程序转成递推程序:

#include<iostream>
#include<algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int maxSum[MAX][MAX];
int n;
int main() {
    int i, j;
    cin >> n;
    for (i = 1; i <= n; i++)
        for (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] << endl;
}
进一步进行空间优化     
没必要用二维maxSum数组存储每一个MaxSum(r,j),只要从底层一行行向上递推,那么只要一维数组maxSum[100]即可,即只要存储一行的MaxSum值就可以。
进一步考虑,连maxSum数组都可以不要,直接用D的第n行代替maxSum即可。节省空间,时间复杂度
#include<iostream>
#include<algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int * maxSum;
int n;
int main() {
    int i, j;
    cin >> n;
    for (i = 1; i <= n; i++)
        for (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] << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值