浅谈动态规划
前言
本蒟蒻认为,在算法竞赛中,最重要的两个算法就是动态规划和搜索。后者可以暴力骗分,也可通过剪枝或记忆化、迭代加深等优化来解决问题。而前者则可以在非指数级时间复杂度内解决许多抽象而复杂的问题。
定义
动态规划($$DP,Dynamic Programming$$)是求解决策问题最优解的算法。
一般来说,动态规划可被拆分成三个部分:状态,决策,阶段。也有三个基本条件:子问题重叠性,无后效性,最优子结构性质。
1.状态、决策、阶段:
为了降低求解的时间复杂度,动态规划算法把原问题视作若干个重叠子问题的逐层递进,每个子问题都有一个状态,构成整个问题的一个阶段,并通过不同的决策方案向更深层问题转移。
2.子问题重叠性、无后效性、最优子结构性质
动态规划将问题分成了若干个子问题,而这些子问题的解决方案被储存在一个表中,而不是需要时再重复计算(类似于记忆化搜索)。而当一个问题,没有共同的子问题,也就是说,其所有的子问题都需要重新计算(无子问题重叠性),那么动态规划是没有用的。
在动态规划中,一个子问题通过决策转移至后续问题,而这个子问题不能被后续问题所影响,这就是无后效性。也就是说,如果将动态规划的状态转移成一张图,那么这张图应该是一张有向无环图,而转移顺序应该是这张图的拓扑序
对于一个问题,它可以由多个子问题到达,也就是说,下一阶段的最优解应该能够由前面各阶段子问题的最优解导出,这个条件被称作最优子结构。对于一个问题,其的最优解是由前阶段最优子状态,再与最优转移决策综合而来。
类别与优化
对于动态规划,本蒟蒻把其分为了这几个类别
1.线性DP
2.区间DP
3.树形DP
4.状压DP
5.计数DP
6.数位DP
而DP的转移有时需要时空上的优化,如:
1.优化状态
2.数据结构优化
3.单调栈、队列优化
4.斜率优化
5.四边形不等式
6.优化枚举顺序
7.倍增优化
一般步骤
1.确定一个无后效性、可高效转移的状态
2.确定枚举顺序以及初始值
3.确定转移方式
4.确定答案由哪些状态得来
例:0/1背包问题
1.设F[i]为包内体积为i时能获得的最大状态
2.先遍历每个物品,又由于每个物品只能选一次,所以枚举体积需要倒序枚举
3.F[j]这个状态可以由该物品不选到达,也可以由选择该物品到达,也就是F[j] = max(F[j],F[j-v[i]]+w[i]);
4.答案是所有状态的最大值
总结:
动态规划一直是算法竞赛中的重点。著名的算法学家、JDOI滴神——QYB曾说过:''想不出来就想动态规划''
动态规划的应用十分广泛,但也需要极强的抽象思想,才能设定出高效的状态与转移方程
最后,分享一下我特别喜欢的一句话:
你的一个又一个阶段是由上天安排的,而你,决定的是在这一阶段可以由上一阶段的哪些状态转移而来。越勤奋,越幸运,并不代表这一次你决策的方向有多么优秀,却代表着现在的这一个状态能够续写多少可能的结果
——《动态规划》