应用动态规划思想解决实际问题

本文通过数字三角形问题和构造回文问题,介绍动态规划的实际应用。从递归到记忆化搜索再到递推,详细解析动态规划的解题思路,并总结动态规划的核心思想和特性。
摘要由CSDN通过智能技术生成

从概念和原理出发去学习某个知识点,往往有种晦涩、无从下手的感觉,本文列举两个示例,从实际应用的角度来理解“动态规划”思想。

数字三角形问题

“数字三角形”是动态规划的经典入门问题:

问题描述:
            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

输出描述:输出路径的最大和
30

分析:我们用一个二维数组来存储数字三角形,其中D[i][j]表示第i行第j个数字(i, j从1开始算)。用MaxSum(i, j)表示从D[i][j]到底边的各条路径中最佳路径的数字之和,所以本题即为求MaxSum(1, 1),是一个典型的递归问题。

1.递归
由题意,当从D[i][j]出发时,下一步的选择只能是D[i + 1][j]或D[i + 1][j + 1]。所以,对于n行的三角形,可得到以下递归式:

// 如果D[i][j]就在底边,则其MaxSum的值即为它本身
if(i == n)
    MaxSum(i, j) = D[i][j]
// 如果D[i][j]不在底边,则其MaxSum的值为它左下和右下元素的MaxSum值的较大者加上它本身
else
    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 101 

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

递归的思路简单,但由于存在大量重复计算,时间复杂度很高(O(2^n))。例如下图,我们从第二行的数字3和8出发,求其到底边的最佳路径之和时,均需要计算一次第三行数字1到底边的最佳路径之和,重复计算浪费了时间。

这里写图片描述

2.记忆递归型的动态规划:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值