像全部的新手同样,对一种算法思想的理解须要经历从肤浅(流于表面形式)到逐渐触摸到本质的过程。为何说逐渐触摸到本质,是由于不少时候你并不肯定一个解释是否是最本质的,有时候会有好几个等价的解释,各自在不一样的场景下具备。
动态规划经典题集转]动态规划与排列组合,好比对动态规划(DP)的理解,一开始我理解为递推,但实际上这是最肤浅的理解,对于如何在特定的问题中找到递推关系毫无帮助和。换言之,这只是一个描述性的总结,而不是一个建设性的总结,不含方。
作(看)了一些题目以后我开始总结关于How的方法,怎样寻找到递推关系(递推关系蕴含着子问题)。获得一个简单的观察,若是一个问题里面含有n这个变量,考虑把n变成n-1的状况。
固然,这个方法常特殊(狭窄)的。实际上更具通常性的方法是不只能够从n-1后面切一刀,还能够在任意地方切(譬如切成两个n/2规模的),以任意标准切(好比像快排那样的)。全部考虑各类切法中哪一种可以最有利于创建子问题是有帮助的。
这个我姑且把它叫作经过直接切分问题来寻找子问题。
但是。这仍是特殊了。由于显然这个方法不能解决全部的DP问题,连多数DP问题都未必能解决。譬如你们熟悉的最大(小)和连续子序列问题,就难以经过这种方法求解(可行,但思惟难度较大。);再譬如上次Lee给的敲石头问题,以及DD出的不听话的机器人问题。所以,在知道了这几个问题的解法以后我继续思考这些解法里面是否是蕴含着更具通常性的解题方法。
看起来我找到了一个,就是分类讨论法,具体作法是:首先,写出可行解的通常形式,譬如a1,a2,...,an。而后对其中的某个不肯定的ai进行讨论。譬如旅行商问题里面对下一个城市进行讨论。当不肯定时,讨论。讨论的每一个分支都带来了进一步的肯定性,从而将问题成一个子问题。
而后Lee提到,这个方法是自顶向下的,有时候不适于思考,譬如对敲石头问题。并提到一种自底向上,着重于构造状态的外推法。
因而,到目前为止,DP的通常性式思考方法就已经有了三种:
1.经过直接对问题切分来探索子问题。
3.经过创建状态来自底向上地推导最终解。
但是,我内心仍是不踏实,由于离散的知识是极其不利于记忆的,须要更多的才能在运用的时候情不自禁的联想起来,并且也容易遗忘。每次作DP题的时候,我都得把好几种指导性的思一一费劲从脑壳里翻出来,而后尝试。实在很不爽。虽然DP题也许并无万用的解题手法,但我仍是但愿可以尽可能提取出不一样手法之间的本质联系,若是可以将一组看上去离散的知识点统一在一个更具通常性,更本质的知识点下面,咱们的知识树就多出了一个根节点,因而下次提取的时候只要提取出那个根节点,下面的几个子节点就会一一乖乖闪现,极大的下降记忆的复杂性。
那么,三种手法的本质联系究竟是什么呢?有一次在上走的时候我想出了一种解释。它也许不是最本质的,也许大牛们早就想到过,可是我以为至少有两个好处:
1.它涵盖以上三种手法,经过增长一个根节点,减小知识的记忆复杂性和易提取性。
2.概括抽象的过程自己就是一种锻炼,锻炼的是概括抽象的能力。
动态规划经典题集这个解释就是:大多DP问题的可行解的形式是一个排列组合(典型的——旅行商问题、最短径问题)。你们都知道,穷举一个规模为N的排列组合复杂性是a^n的,也就是组合复杂性。而求解DP问题的核心步骤:发现“子问题”,这个“子问题”实际上就是对应最终解的那个排列组合的某个子排列组合(某种子集);而这里的“子排列组合”的数目则每每是多项式的(silwile,,指出并不是老是如此),这就是为何一个组合复杂性的穷举问题能够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题彷佛均可以借助这种手法来探索,固然,刚才说过了哈7》惊险二连冠 《格列佛游记》,未必是最快的,因此也许能够考虑用来作后备方案,当其它方案没有头绪的时候试试。
个人解题经验还颇有限,因此不清楚这个手法的覆盖范围有多广。实际上一个更广的领域是组合优化。更提到的很像。但针对的问题就不只止于DP了。
你说得没错。用空间换时间是DP的一个重要性质,事实上,它仍是许多算法的一个性质。因此说,“用空间换时间”并无“充分”地描述DP的特色,更没有对“如何探索一个DP问题的解”提供建设性的帮助。对于后者,如何寻找递推关系或“子问题”才是重点,一旦找到了子问题以后经过缓存子问题的解来优化复杂度就相对比较trivial了。
DP的思想理解起来容易,一开始的时候我看了几本书的DP章节,以为,哦,这很容易,递推嘛。但真正本身作题的时候,发现寻找递推关系是最困难的一步,non-trivial的DP题里面递推关系并非显而易见的。
TopLang里面也有人推荐《算法艺术与信息学竞赛》,但提到里面的题目偏难,不适合初学者。做为题集应该仍是不错的。听说几本众所周知的经典算法书里面最适合程序员学习的是《AlgorithmDesign》,如下引一段g9的介绍:
我也喜欢AlgorithmDesign这本书。我的以为很是适合初学者和程序员。书一开始就给出稳定婚姻问题。从解决问题的角度入手,层层递进地怎么设计,引出算法设计的通常方法。而后用几道常见题目引入经常使用算法的设计思。奠基总纲后,后面的书就从不一样的角度深化算法设计的方法。例题也有趣。我的至关喜欢从设计到分析的思。这种方法给读者(至少是程序员)诱人的动机。毕竟不少人读算法书是为了写出更强大的程序。尤为像我这种老人家,NADD症状严重,尤为须要使人信服的动机,否则就老走神。并且做者强调设计,反而提供了钻研算法分析的充分理由,很好地解释了要设计出正确高效的算法,形式化的分析是必要手段。为什要扩展?为何要处处一堆引理?为何要追究复杂度?为何要泛化?为何要特化?这些看来学究的行为天然地有了现实基础。加上这本书写得晓畅通透,就算你只看书不动手,也能够得到好舒服,原来我也能够设计出这些算法啊。一点都不难嘛这种相似后的波浪状快感和。:-D
DP的思想理解起来容易,一开始的时候我看了几本书的DP章节,以为,哦,这很容易,递推嘛。但真正本身作题的时候,发现寻找递推关系是最困难的一步,non-trivial的DP题里面递推关系并非显而易见的。[/quote]
又碰到一个有上思考习惯滴。我想做者想描述的本质可能在于,如何识别一个问题是DP能够用DP解决的,因此顺着这种想法,天然就像探究DP的本质,由于一旦探究了DP的本质就能够迅速的对须要解决的问题进行定位,而后解决。好比一个很难的题目,咱们告诉应试者能够用DP解决,也许他很快能想到答案,若是咱们不说呢,也许他搞不定。认清DP的本质就有助于咱们判断某个问题是否用DP能够解决,我想这是楼主的本意吧。raymond程序员
来源:http://blog.csdn.net/cangchen/article/details/45045633算法