欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ACM总结——动态规划

程序员文章站 2024-03-13 12:06:21
...

动态规划(dynamic programming)简称DP。

先看几个简单的问题:

1,斐波那契数列

1,1,2,3,5,8......

求第n项

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

时间复杂度O (1.6 ^ n)

递归写法(备忘录法):

int ans[1000]={0};
int fac(int n)
{
    if(n<3)return 1;
    if(ans[n])return ans[n];
    return ans[n]=fac(n-2)+fac(n-1);
}

非递归写法:

int ans[1000]={0,1,1};
int fac(int n)
{
    for(int i=3;i<=n;i++)ans[i]=ans[i-1]+ans[i-2];
    return ans[n];
}

递归写法不需要控制DP的计算顺序,非递归写法需要严格控制计算顺序。

读者可此处思考一下上述递归写法的实际计算顺序,假设编译器是默认先执行加法左边的,再执行加法右边的。

两种写法的时间复杂度都是O(n)

为什么差异这么大?

这就是DP的第一个重要特性:重叠子问题

 

2,求数列中位数

这个题,能不能像上一题这么做呢?

如果我用f(n)表示数列前n个数的中位数,那么,由f(n-1)和f(n-2)可以直接推导出f(n)吗?

不能!

差异在哪?差异在于问题本身的性质不同。

这种由子问题的答案可以直接推导出原问题答案的性质,其实就是最优子结构。

最优子结构:问题的最优解包含了子问题的最优解

 

再来看看一个动态规划的题目,当我们分析它的时候,我们在想些什么?

3,数列的DP问题

一维

力扣 OJ 300. 最长上升子序列

https://blog.csdn.net/nameofcsdn/article/details/104086350

力扣OJ 1218. 最长定差子序列

https://blog.csdn.net/nameofcsdn/article/details/106418150

二维

力扣 OJ 1143. 最长公共子序列

https://blog.csdn.net/nameofcsdn/article/details/104091938

CSU - 1060 Nearest Sequence (三个数组的最长公共子序列)CSU - 1060 Nearest Sequence (三个数组的最长公共子序列)

https://blog.csdn.net/nameofcsdn/article/details/79697208

 

4,最短路问题

ACM总结——动态规划

ACM总结——动态规划

 

动态规划的题目,当我们分析它的时候,主要就是:

问题研究的对象、问题的子问题、最优子结构(即递推式)、解空间结构

递归写法和非递归写法其实都是解空间的遍历,而绝大部分问题的解空间都可以映射为树空间,树的遍历主要就是DFS和BFS,递归基本上就是DFS。

 

什么是解空间结构?

解空间就是问题可能的解组成的集合,根据问题的属性,空间的结构也有不同,有的是数组有的是树等等。

 

 

 

按照问题研究的对象类型和解空间结构,DP问题可以分为数列DP、区间DP、树形DP、数位DP、状态压缩DP、概率与期望DP、高维DP等等。

 

DP的更深用法:

空间压缩、时间优化

相关标签: new