ACM动态规划基础篇

本文介绍了动态规划的基础知识,包括最优化原理、无后效性和重叠子问题的特征。通过斐波那契数列、最短向上路径、最长曼哈顿路径等问题,详细阐述了动态规划的应用。此外,还探讨了记忆化搜索与动态规划的关系,并以背包问题为例,讨论了01背包、完全背包和多重背包问题的动态规划解决方案。最后,讲解了最长不降子序列LIS的求解方法,包括O(n^2)和O(nlogn)的算法。
摘要由CSDN通过智能技术生成

1 前言

1.1 什么是动态规划

动态规划(Dynamic Programming)是求解决策过程最优化的数学方法。把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。

1.2 什么时候要用动态规划

如果要求一个问题的最优解(通常是最大值或者最小值),而且该问题能够分解成若干个子问题,并且小问题之间也存在重叠的子问题,则考虑采用动态规划。

能采用动态规划求解的问题的一般要具有3个性质:

  • 最优化原理
    如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
  • 无后效性
    即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
  • 有重叠子问题
    即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

2 斐波那契数列 F i b o n a c c i Fibonacci Fibonacci

2.1 引入

有一头母牛,它每年年初生一头小母牛。每头小母牛从第二个年头开始,每年年初也生一头小母牛。请问在第n年的时候,共有多少头母牛?

2.2 定义

f i b ( n ) = f i b ( n − 1 ) + f i b ( n − 2 ) fib(n) = fib(n - 1) + fib(n - 2) fib(n)=fib(n1)+fib(n2)

0 0 0 1 1 1 1 1 1 2 2 2 3 3 3 5 5 5 8 8 8 13 13 13 21 21 21 34 34 34

2.3 递归分治解决 R e c u r s i o n Recursion Recursion

2.3.1 代码

int fib(n){
   
    return (n < 2) ? n : fib(n - 1) + fib(n - 2);
}

int fib(n){
   
    if(n < 2) return n;
    return fib(n - 1) + fib(n - 2);
}

2.3.2 时间复杂度分析

斐波那契数列递归求解

T ( n ) = T ( n − 1 ) + T ( n − 2 ) + 1 &gt; 2 ⋅ T ( n − 2 ) + 1 = O ( ( 2 ) n ) T(n) = T(n - 1) + T(n - 2) + 1 \gt 2 \cdot T(n - 2) + 1 = O((\sqrt{2})^n) T(n)=T(n1)+T(n2)+1>2T(n2)+1=O((2 )n)

T ( n ) = T ( n − 1 ) + T ( n − 2 ) + 1 = O ( f i b ( n ) ) = O ( Φ n ) T(n) = T(n - 1) + T(n - 2) + 1 = O(fib(n)) = O(\varPhi ^ n) T(n)=T(n1)+T(n2)+1=O(fib(n))=O(Φn)

Φ = 1 + 5 2 = 1.618... \varPhi = \frac{1 + \sqrt{5}}{2} = 1.618... Φ=21+5 =1.618...

Φ 36 ≈ 2 25 \varPhi^{36} \approx 2^{25} Φ36225

Φ 5 ≈ 10 \varPhi^{5} \approx 10 Φ510

凉了呀

2.4 解决方案

刚刚递归算法的不足之处在于重复计算了大量相同的子问题,浪费了大量时间

大量重复子问题

好记性不如烂笔头

记忆化搜索 M e m o i z a t i o n Memoization Memoization

备忘录 L o o k − u p Look-up Lookup T a b l e Table Table → \to A r r a y Array Array

用一个数组记录需要重复计算的子问题

这就是动态规划的第一种实现方式,也是最容易理解的写法:记忆化搜索

2.5 记忆化搜索

const int maxn = 1e6 + 5;
int f[maxn];
void init(){
   
    memset(f, -1, sizeof(f));
    f[0] = 0;
    f[1] = 1;
}
int fib(n){
   
    int& ret = f[n]
    if(ret != -1) return ret;
    ret = fib(n - 1) + fib(n - 2);
    return ret;
}

记忆化搜索后的计算过程

3 快速幂

3.1 问题描述

a 98765 = ? ? ? a^{98765} = ??? a98765=???

3.2 十进制快速幂

a 9 ⋅ 1 0 4 + 8 ⋅ 1 0

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值