动态规划

前言

    谈到动态规划,其实最好的切入方向,就是先了解一下最经典的几个例子;找出这些例子的共性;再凝聚这些特征进行模型的分类;分类完成后,在每个分类里面学几个经典的例题。例题选好了,就可以去刷 leetcode。这样下来;动态规划的水平也就形成了。

阶段一:入门了解的例子

例1:求第 n 个斐波那契数列

方法一:递归

既然递归式子都列出来了,那么最直男的方法必定就是它了,不多讲。

方法二:将递归改成循环

可以注意到,递归的方法是一种从后 f(n)往前形成生成树的方法,这里面会产生很多不必要的重复计算;当我们将递归改为从1开始到n的循环的时候,也就是从前往后的方法,就可以避免一些不必要的重复计算,也就可以降低时间复杂度了。

方法三:将递归改成动态规划

斐波那契数列问题是递归的;考虑它有一个特别突出的结构特性。就是它具有:

  • 重叠子问题。(这也是动态规划的要素之一)
  • 最优子结构。(这一点貌似。。但是尽管这不是优化问题,但套用还是没有问题的)
long long memo[N+1];        // 全局变量,初始化为0
long long fib(unsigned n)
{
    if (n <= 1)
        return n;
    if (memo[n]) return memo[n];
    else
        return memo[n] = fib(n-1) + fib(n-2);
}

----------------

 

 

例2. 求最短的路径问题

方法一:枚举算法:如果网络层数为 n 。复杂度接近2的n次方。

方法二:动态规划算法:

这里关键是利用了两个动态规划的要素:

  • 更大问题的最优结果可以利用其子问题的最优结果。(最优子结构)
  • 重叠子问题。
  •  

 

例3  矩阵相乘 最优顺序

题目:

给定n个矩阵{A1,A2,A3...An};其中Ai,Ai+1是可乘的。但是你可以加括号来改变它们相乘的顺序。请确定一个顺序来使这个连乘的计算量最小?

我将就本题,给出标准的动态规划设计步骤:

前提:读懂题意,知道两个矩阵相乘的计算量主要体现在(前一个矩阵的行*列 * 后一个矩阵的 列)

1)找出最优解的大概的整体形式(主要是看看子问题和整体最优解)之间的结构特征,期间要做的就是把整个问题求解变量化,设计出边界和分隔的点。

回到本题就是:

数据模型化:将{A1,A2,A3...An}简写成A[1-n]的形式;假设在k处分割成两个子问题,当我们一般化 A[i,j]时,k的取值范围也确定在 i <= k <= j-1 之间。

找出最优解与次子结构的关系式:最优解 = 子问题1的最优解 + 子问题2的最优解 + 此时子问题1的大矩阵和子问题2的大矩阵相乘的计算量

这里的最优解,就在于我们确定k的位置。在循环里面逐个尝试。。。

2)列出具体的递归关系(整体的递归形式解)

方便起见:设A[i,j]的最优解是 m[i,j];

由于原问题的矩阵连乘形式是A[1,n]的形式;故这里可以确定 1<= i <= j <n;注意到当子问题的 i==j 时,m[i,j]=m[i,i]= 0(单个矩阵没有计算量)

当i<j时,说明子问题还没有解决,还可以分解。

m[i,j] =\binom{0..................................................................i=j}{min(m[i,k] ,m[k+1,j])+p_{i-1}p_{k}p_{j}.............i<j}

 

到这里这个问题的递归解可以得出,代码如下:

# 本题的递归求解程序
def recsolution(i, j):
    ans = []
    if i == j:
        return 0
    else:
        for k in range(i, j):
            opt = recsolution(i, k) + recsolution(k+1, j) + s[i-1]*s[k]*s[j]
            if not ans:
                ans = opt
            else:
                if opt < ans:
                    ans = opt
        return ans


ans = []
s = [30, 35, 15, 5, 10, 20, 25]
print(recsolution(1, 6))

3)用动态规划优化递归

因为重复计算,递归的复杂度可想而知:

由于这个题它满足:

  • 最优子结构
  • 重叠子问题

所以在此,我们用动态规划去优化:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值