动态规划(DP)C++讲解,看着这一本就够了

什么是动态规划

用于求解某种最优性质的问题。

将带求解问题分解为若干个子问题,解决子问题,然后从这些子问题的解得到原问题的解

两个要素:状态和转移。

阶段 :求解的问题的每个过程。

状态 :状态表示每个阶段所处的情况。

策略 :策略是按顺序排列的策略组成的集合。 状态转移方程 ;状态转移方程是确定过程由一个状态到另一个状态的过程。 

什么时候使用动态规划

最优子结构性质:如果问题的最优解所包含的子问题的解也是最优的,那么该问题具有最优子结构性质。(LIS)

子问题重叠性质:子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。(求Fibonacci)

无后效性:对于某个阶段状态,只能由前面的状态转移到,且不可以转移到前面。(对于有负边权求最短路,dijkstra是不可做的)\

动态规划是干什么的

DP常常适用于有重叠子问题和最优子结构性质的问题。

这时候就有许多同学,就开始问了:那他的步骤呢

很简单

设状态 列转移方程

今年普及组的同学注意了

常见动态规划类型有

背包问题

LIS

LCS

括号序列计数

区间DP

树形DP

数位DP

状压DP

概率期望DP

那我们就开始今天的练习

爬楼梯问题

一个人每次只能走1层楼梯或者2层楼梯,问走到第n层楼梯一共有多少种方法。

n<=1000000

数楼梯 - 洛谷https://www.luogu.com.cn/problem/P1255Fibonacci。

设状态:f[i]表示走到第i层的方案数。

列转移方程:

f[i] = f[i-1]+f[i-2]

边界条件:

f[0] = 1, f[1] = 1;

记忆化搜索

复杂度分析(评价一个动态规划算法设计的好坏):

 空间复杂度: O(N)

 转移复杂度:O(1)

总复杂度:O(N)

疯狂的爬楼梯问题

 一个人每次只能走2层楼梯,22层楼梯,222层楼梯,问走到第n层楼梯一共有多少种方法。

n<=1000000

 那这到题该怎么做呢

设状态:f[i]表示走到第i层的方案数。

列转移方程:

f[i] = f[i-2] + f[i-22] + f[i-222]

边界条件:

f[0] = 1 f[1] = 1

复杂度分析(评价一个动态规划算法设计的好坏):

 空间复杂度:O(N)

转移复杂度:O(1)

总复杂度:O(N)

超级疯狂的爬楼梯问题

一个人每次最少走1层楼梯,最多t层楼梯。

问走到第n层楼梯一共有多少种方法。

n<=1000000

其中有许多层楼梯上会有石头,求最少经过多少石头到达n层。 比如第1层有2个石头,第2层有10个石头,第3层有2个石头,每次最多走两层。

那么显然0-1-3只需要经过4个石头

n<=1000000

设状态:f[i]表示到第i层最少经过多少石头。

列转移方程 如果i处没有有石头

 f[i] = min(f[i – 1], f[i – 2] … f[i-k])

如果i处有石头

f[i] = min(f[i-k]) + a[i]

(a[i]为第i层的石头)

复杂度:

空间:O(N)

转移:O(K)

总复杂度:O(N*K)

LIS 最长上升子序列

给出一个序列,求出最长的不下降子序列的长度

n<=1000

2,7,3,4,8,5 2,3,4,5

answer = 4

2533 -- Longest Ordered Subsequencehttp://poj.org/problem?id=2533[NOIP2004 提高组] 合唱队形 - 洛谷https://www.luogu.com.cn/problem/P1091

LIS 解法

设状态:f[i]表示到第i个位置的最长上升子序列。

列转移方程:

f[i] = max(f[j])+1,   j<=i且h[i]>h[j]

复杂度:

空间:O(N)

转移:O(N)  

总复杂度:O(N^2)

LIS nlogn解法

g[i]表示所有长度为i的最长上升子序列中,末尾元素最小的是多少。

g[i]是递增的。 那么对于第i个数x,在g数组中找到第一个小于它的数就好了。

即g[j]<=x的最大的j(也就是x能够正好插入的位置) 令g[j+1]=min(g[j+1],x);

二分查找优化,复杂度为nlogn

LIS 合唱队形

[NOIP2004 提高组] 合唱队形 - 洛谷https://www.luogu.com.cn/problem/P1091

求一遍最长上升子序列和最长下降子序列,扫一遍统计答案。

你可能感兴趣的:(算法,动态规划,c++)