动态规划算法

简介:
斐波纳契数列F(n)

n

0

1

2

3

4

5

6

7

8

9

10

F(n)

1

1

2

3

5

8

13

21

34

55

89

递归 vs 动态规划

递归版本(太慢):

int f(int n)
{
    if(n <= 1) return 1;
    else return f(n-1)+f(n-2);
}

动态规划版本(有效率!算法复杂度是 O(n)):

int a[1000];
int f(int n)
{
    a[0]=a[1]=1;
    for(int i=2; i<=n; i++)
        a[i]=a[i-1]+a[i-2];
    return a[n];
}

方法概要

构造一个公式,它表示一个问题的解是与它的子问题的 解相关的公式.   E.g.  F(n) = F(n-1) + F(n-2).

为这些子问题做索引 ,以便它们能够在表中更好的存储与检索 (i.e., 数组array[])

以自底向上的方法来填写这表格; 首先填写最小子问题的解.

这就保证了当我们解决一个特殊的子问题时, 可以利用比它更小的所有可利用的 子问题的解.

动态规划算法原理

算法思想:

将待求解的问题分解成若干个子问题,并存储子问题的解而避免计算重复的子问题,并由子问题的解得到原问题的解。

动态规划算法通常用于求解具有某种最优性质的问题。

动态规划算法的基本要素:最优子结构性质和重叠子问题。

原理:

最优子结构性质:问题的最优解包含着它的子问题的最优解。即不管前面的策略如何,此后的决策必须是基于当前状态(由上一次决策产生)的最优决策。

重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些问题被反复计算多次。对每个子问题只解一次,然后将其解保存起来,以后再遇到同样的问题时就可以直接引用,不必重新求解。

解决问题的基本特征:

1. 动态规划一般解决最值(最优,最大,最小,最长……)问题;

2. 动态规划解决的问题一般是离散的,可以分解(划分阶段)的;

3. 动态规划解决的问题必须包含最优子结构,即可以由(n-1)的最优推导出n的最优

解决问题的基本步骤:

动态规划算法的4个步骤:

1. 刻画最优解的结构特性. (一维,二维,三维数组)

2. 递归的定义最优解. (状态转移方程)

3. 以自底向上的方法来计算最优解.

4. 从计算得到的解来构造一个最优解.

举例实战

例题一.   斐波纳契数列F(n)

步骤1:用F(n)表示在斐波纳契数列中第n个数的值;

步骤2:状态转移方程:

 

步骤3:以自底向上的方法来计算最优解

n

0

1

2

3

4

5

6

7

8

9

10

F(n)

1

1

2

3

5

8

13

21

34

55

89

步骤4:在数组中分析构造出问题的解;

例题二.   输入n,求出n!

步骤1:用F(n)表示n!的值;

步骤2:状态转移方程:

步骤3:以自底向上的方法来计算最优解

n

0

1

2

3

4

5

6

7

8

9

10

F(n)

1

1

2

6

24

120

720

       

例题三:排队买票问题

一场演唱会即将举行。现有n个歌迷排队买票,一个人买一张,而售票处规定,一个人每次最多只能买两张票。假设第i位歌迷买一张票需要时间 Ti(1≤i≤n),队伍中相邻的两位歌迷(第j个人和第j+1个人)也可以由其中一个人买两张票,而另一位就可以不用排队了,则这两位歌迷买两张票的时 间变为Rj,假如Rj<Tj+Tj+1,这样做就可以缩短后面歌迷等待的时间,加快整个售票的进程。现给出n, Tj和Rj,求使每个人都买到票的最短时间和方法。

分析:

如果前i个人买票的最优买票方式一确定,比如第i-1个人买一张票,则前i-1个人的买票方式也一定是最优的。即问题的最优解包含子问题的最优解。

步骤1:用F(i)表示前i个人买票的最优方式,即所需最短时间;现在要决定F(i)需要考虑两种情况:

(1)第i个人的票自己买

(2)第i个人的票由第i-1个人买

步骤2:状态转移方程:

步骤3:以自底向上的方法来计算最优解

程序的实现(伪代码):

BuyTicks(T, R)
1    n ← length[T] 
2    f[0] ← 0
3    f[1] ← T[1]
4    for i ← 2 to n do 
5                 f[i] ← f[i-2]+R[i-1]
6                 if  f[i] > f[i-1]+T[i] then 
7                     f[i] ← f[i-1]+T[i]
8    return f
目录
相关文章
|
3月前
|
存储 算法
深入了解动态规划算法
深入了解动态规划算法
86 1
|
3月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
6月前
|
算法 开发者 Python
惊呆了!Python算法设计与分析,分治法、贪心、动态规划...这些你都会了吗?不会?那还不快来学!
【7月更文挑战第10天】探索编程巅峰,算法至关重要。Python以其易读性成为学习算法的首选。分治法,如归并排序,将大问题拆解;贪心算法,如找零问题,每步求局部最优;动态规划,如斐波那契数列,利用子问题解。通过示例代码,理解并掌握这些算法,提升编程技能,面对挑战更加从容。动手实践,体验算法的神奇力量吧!
78 8
|
6月前
|
算法 Python
算法不再难!Python分治法、贪心、动态规划实战解析,轻松应对各种算法挑战!
【7月更文挑战第8天】掌握Python算法三剑客:分治、贪心、动态规划。分治如归并排序,将大问题拆解递归解决;贪心策略在每步选最优解,如高效找零;动态规划利用子问题解,避免重复计算,解决最长公共子序列问题。实例展示,助你轻松驾驭算法!**
78 3
|
2月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
67 2
|
3月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
127 2
动态规划算法学习三:0-1背包问题
|
3月前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
86 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
3月前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
199 0
动态规划算法学习二:最长公共子序列
|
3月前
|
存储 人工智能 算法
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
|
3月前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
207 0

热门文章

最新文章