`
61party
  • 浏览: 1051865 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

动态规划与排列组合

阅读更多

动态规划与排列组合

By 刘未鹏(pongba)

C++的罗浮宫(http://blog.csdn.net/pongba)

TopLanguage(http://groups.google.com/group/pongba)

像所有的新手一样,对一种算法思想的理解需要经历从肤浅(流于表面形式)到逐渐触摸到本质的过程。为什么说"逐渐"触摸到本质,是因为很多时候你并不确定一个解释是不是最本质的,有时候会有好几个等价的解释,各自在不同的场景下具有启发。

比如对动态规划(DP)的理解,一开始我理解为"递推",但实际上这是最肤浅的理解,对于如何在特定的问题中找到递推关系毫无帮助和启发。换言之,这只是一个描述性的总结,而不是一个建设性的总结,不含方法论。

做(看)了一些题目之后我开始总结关于"How"的方法,怎样寻找到递推关系(递推关系蕴含着子问题)。得到一个简单的观察,如果一个问题里面含有n这个变量,考虑把n变成n-1的情况。

当然,这个方法是非常特殊(狭窄)的。实际上更具一般性的方法是不仅可以从n-1后面切一刀,还可以在任意地方切(譬如切成两个n/2规模的),以任意标准切(比如像快排那样的)。所有考虑各种切法中哪种能够最有利于建立子问题是有帮助的。

这个我姑且把它叫做通过直接切分问题来寻找子问题。

可是。这还是特殊了。因为显然这个方法不能解决所有的DP问题,连"多数"DP问题都未必能解决。譬如大家熟悉的"最大(小)和连续子序列"问题,就难以通过这种方法求解(可行,但思维难度较大。);再譬如上次Lee给的敲石头问题,以及DD出的不听话的机器人问题。因此,在知道了这几个问题的解法之后我继续思考这些解法里面是不是蕴含着更具一般性的解题方法

看起来我找到了一个,就是分类讨论法,具体做法是:首先,写出可行解的一般形式,譬如a1, a2, ..., an。然后对其中的某个不确定的ai进行讨论。譬如旅行商问题里面对"下一个城市"进行讨论。当不确定时,讨论。讨论的每个分支都带来了进一步的确定性,从而将问题转化成一个子问题。

然后Lee提到,这个方法是自顶向下的,有时候不适于思考,譬如对敲石头问题。并提到一种自底向上,着重于构造"状态"的外推法

于是,到目前为止,DP的一般性启发式思考方法就已经有了三种:

1. 通过直接对问题切分来探索子问题。
2. 通过对可行解的分类讨论来探索子问题。
3. 通过建立"状态"来自底向上地推导最终解。

可是,我心里还是不踏实,因为"离散"的知识是极其不利于记忆的,需要更多的练习才能在运用的时候"不由自主"的联想起来,而且也容易遗忘。每次做DP题的时候,我都得把好几种指导性的思路一一费劲从脑袋里翻出来,然后尝试。实在很不爽。虽然DP题也许并没有万用的解题手法,但我还是希望能够尽量提取出不同手法之间的本质联系,如果能够将一组看上去离散的知识点统一在一个更具一般性,更本质的知识点下面,我们的知识树就多出了一个根节点,于是下次提取的时候只要提取出那个根节点,下面的几个子节点就会一一乖乖闪现,极大的降低记忆的复杂性。

那么,上面三种手法的本质联系到底是什么呢?有一次在路上走的时候我想出了一种解释。它也许不是最本质的,也许大牛们早就想到过,但是我觉得至少有两个好处:

1. 它涵盖以上三种手法,通过增加一个根节点,减少知识的记忆复杂性和易提取性。
2. 归纳抽象的过程本身就是一种锻炼,锻炼的是归纳抽象的能力。

这个解释就是:大多DP问题的可行解的形式是一个排列组合(典型的——旅行商问题、最短路径问题)。大家都知道,穷举一个规模为N的排列组合复杂性是a^n的,也就是"组合复杂性"。而求解DP问题的核心步骤:发现“子问题”,这个“子问题”实际上就是对应最终解的那个排列组合的某个"子排列组合"(某种子集);而这里的“子排列组合”的数目则往往是多项式的(silwile,XuYoug9指出并非总是如此),这就是为什么一个组合复杂性的穷举问题可以DP优化为多项式复杂度的问题。将重复出现的子排列组合对应的子问题的解缓存起来,就是DP的缓存优化了。

此外,这一解释也提供了如何探索子问题的一个通用方案:寻找形式相同的子排列组合。还是拿最大和连续子序列说事,其解的形式是:A[i], A[i+1], .., A[j-1], A[j],其中i,j不确定。那么如何得到形式相同的子组合呢?首先讨论A[j],为什么要讨论,因为只要A[j]不确定,A[j-1]就不确定,就拿不出子组合来。对于一个确定的A[j0],解的可能性为A[i], A[i+1], .., A[j0-1], A[j0]。其最优解依赖于子组合A[i], A[i+1], .., A[j0-1],到这里子问题就不请子现了:A[i], A[i+1], .., A[j0-1], A[j0]和A[i], A[i+1], .., A[j0-1]的形式相同,意味着它们是同一个问题的不同阶表示。

当然,由于这个指导思想一般性大了点,所以实际问题中往往没有前面提到的三种手法寻找方案来得快——众所周知的是,越特定的手法解题面虽然越窄,但如果题目对口了解决起来也越快。但它至少有两个好处(前面说过了)。所以考虑一般性和特殊性的手法都是有帮助的。

类似的,敲石头问题也可以通过这种手法来探索子问题。至少目前我做过的DP题似乎都可以借助这种手法来探索,当然,刚才说过了,未必是最快的,所以也许可以考虑用来做后备方案,当其它方案没有头绪的时候试试。

我的解题经验还很有限,所以不清楚这个手法的覆盖范围有多广。实际上一个更广的领域是"组合优化"。更上面提到的很像。但针对的问题就不仅止于DP了。

参考

1. 《Introduction To Algorithms》的DP章节。
2. 《Algorithms》的DP章节。
3. 《Algorithm Design Manual》的DP章节。
4. DD的《背包问题九讲
5. wikipedia
6. 网络搜索出来的一堆题目和讲解。(如《动态规划经典题集》)
7. TopLanguage上的帖子:矩阵也疯狂DPDPDPDP(二)

分享到:
评论

相关推荐

    经典 算法思想 穷举法 高精度 动态规划 回溯 贪心 排列组合 排序

    穷举法 高精度 动态规划 回溯 贪心 排列组合 排序

    组合数学的算法与程序设计

    第三章 排列组合信其计数问题 3.1 两个基本计数原理 3.2 排列 3.3 组合 3.4 排列组合问题的一个实验程序 练习三 第四章 容斥原理 4.1 容斥原理的两种形式 4.2 容斥原理的一般形式 4.3 容斥原理的应用 第五章 母函数 ...

    排列组合.zip

    动态规划:动态规划是一种通过将问题分解成更小的子问题来解决复杂问题的算法。常见的动态规划问题包括背包问题、最长递增子序列、编辑距离等。 贪心算法:贪心算法是一种在每一步选择中都采取当前状态下最优决策的...

    常用算法分析设计(分治、动态规划、分支限界、回溯、贪婪等等)

    详细介绍了常用的算法设计法,包括:分治、递归、动态规划、分支限界、回溯、贪婪、排列组合、图论算法等等

    【算法设计分析课程设计】动态规划解决石子合并问题及回溯法解决运动员匹配问题

    针对石子合并问题,本文利用动态规划算法寻求石子合并时的最大,最小得分,选择相邻的两堆石子堆进行合并,其最终花费的代价与石子堆的排列顺序有关。根据其重叠子问题建立状态转移方程,利用程序进行求解。算例结果...

    组合数学和程序设计

    从鸽笼原理到Ramsey理论,排列组合及其计数问题,容斥原理,母函数,递归关系,组合设计,线性规划,动态规划。。。。。

    python 数据结构 算法 LeetCode 牛客 面试 编程之美 动态规划 字典树 快速排序 树 字符串 数组 链表 全排列

    树 * 字典树 * 遍历-层次遍历 * 遍历-中序遍历-非递归 * 遍历-前序遍历-非递归 * 遍历-后序遍历-非递归 * 二叉查找树-两数之和 * 二叉查找树-中第K小的元素 ...排列组合 动态规划 树 链表 数学 位运算 编程之美

    组合数学 pascal 青少年信息学竞赛教程

    组合数学 pascal 青少年信息学竞赛教程 涵盖了回溯 递归 排列组合 卡特兰数 动态规划等

    如何写好数学建模竞赛论文.pdf

    95B天车与冶炼炉的作业调度 动态规划、排队论、图论 96A最优捕鱼策略 微分方程、优化 96B节水洗衣机 非线性规划 97A零件的参数设计 非线性规划 97B截断切割的最优排列 随机模拟、图论 98A一类投资组合问题 多...

    蓝桥杯大赛学习课程资料合集(共七课).zip

    蓝桥杯大赛学习课程及笔记资料合集,共7课。 第一次课程:实用性原则,二阶魔方实例 第二次课程:递归原理,算式符号,反转串等 ...第六次课程:分治法与动态规划等 第七次课程:风险度量、油漆面积、合根植物等

    ACM题库完整版.pdf

    动态规划 贪心算法 分治算法 数学类 数论(素数判定、约数、同余) 组合数学(排列、组合、容斥原理) 线性代数(矩阵运算、行列式) 概率论(事件概率、条件概率) 其他类型 字符串处理(字符串匹配、KMP算法) ...

    algorithm:算法学习~

    记录我在各个网站的算法刷题题解~ ...动态规划 线性dp 背包 01背包 完全背包 多重背包 最长不降子序列 最长公共子序列 最短编辑距离 树形dp 排序 快排 堆排序 希尔排序 归并排序

    列车车厢重排问题.docx

    通常情况下,列车车厢重排问题是一个组合优化问题,可以使用各种算法来求解,如贪婪算法、动态规划、回溯算法、遗传算法等。这个问题在物流和交通领域有着广泛的应用,因为有效地解决了这个问题可以节省时间和资源。...

    Pascal信息竞赛辅导

    排列与组合 第四章 计算几何 第五章 其它数学知识及算法 图论算法 第一章 最小生成树 第二章 最短路径 第三章 拓扑排序(AOV网) 第四章 关键路径(AOE网) 第五章 网络流 第六...

    ACM模板和一些题目的代码实现

    动态规划:通过分解问题为子问题并存储子问题的解,减少重复计算,常用于优化递归解法。代码实现时需定义状态变量和状态转移方程。 图论:研究图的结构和性质的分支。代码可能涉及图的表示(邻接矩阵/邻接表)、遍历...

    python 动态规划实现整数拆分

    (如果计算为两种,那么属于有序拆分,实现起来较为容易,用排列组合中的插板法即可) 可以发现当待拆分数很小时,比较容易枚举出答案。 但是若要将10进行拆分,结果有42种;若要将20进行拆分,结果有627种;若要将...

    NOI/NOIP知识点总提纲

    NOI/NOIP知识点总提纲 包含 0. 算法的时空分析 1. 基础算法 2. 排序算法 3. 查找算法 4. 搜索算法 5. 动态规划 6. 排列组合 7. 数论 8. 线性表 9. 图 …………

    python学习应用手册(上册)

    4、函数、装饰器、偏函数、变量作用域、回调函数、返回函数、闭包、递归、动态规划 5、迭代器与生成器、常用函数总结、高阶函数 6、模块导入、自定义模块、安装第三方模块 7、文件操作、时间日期、日历、随机数、栈...

    ACM比赛注意的知识

    1,离散数学知识的应用(如排列组合、简单的图论,数 理逻辑) 2,数论知识 3,线性代数 4,组合代数 5,计算几何 二 算法 1,排序算法(冒抛法,插入排序,合并排序,快速排 序,堆排序) 2,查找(顺序...

    C语言程序设计大赛资料 - .pdf(0 积 f)

    1,离散数学知识的应用(如排列组合、简单的图论,数理逻辑) 2,数论知识 3,线性代数 4,组合代数 5,计算几何 二 算法 1,排序算法(冒抛法,插入排序,合并排序,快速排序,堆排序) 2,查找(顺序查找,...

Global site tag (gtag.js) - Google Analytics