Dynamic Programming一直以来是自己比较弱的一部分,希望可以在这一块有所提升。
动态规划,Dynamic Programming。这里的programming没有翻译成编程,是因为,这里的programming的意思是指一个tabular method。其实这也暗示了DP的本质,用一个table保存子问题的中间结果。(后面会有例子具体介绍)
和分治算法比较类似,但不同的是分治算法把原问题划归为几个相互独立的子问题,从而一一解决,而动态规划则是针对子问题有重叠的情况的一种解决方案。
目前design DP主要有两个思路:
一个是利用recursive method,即首先把问题用递归的方法解决,然后用一个table保存recursive中的中间结果,这不就避免了递归中重复计算的低效了吗?遇到需要计算以前计算过的东西,直接查表就OK,总之一句话,先写recursive,然后比葫芦画瓢基本就能把DP的方法写出来。这里的难点是如何找到recursive。算法导论里面也给的是这个思路。下面的前三个例子全部出自《算法导论》。
另一个思路是exhaust search,这个好像是我们老师发明的方法,这里有篇Kirk的论文, How to design dynamic programming algorithms sans recursion 有兴趣的大家可以仔细研究一下,我下面也会简单举例介绍一下这个方法。
下面的例子中多数代码都是伪代码,旨在illustrate idea。同时节省时间。代码中都省去了backtrack的过程,即只得到了optimal solution的值,省去了如何construct optimal solution的过程。这个一般用一个数组记录一下就OK了。
转载于:http://www.cnblogs.com/Gavin_Liu/archive/2011/04/13/2011214.html
先来个比较简单的例子(其实后面的也不难O(∩_∩)O~)
例:Rod-cutting problem(切木头问题。感觉翻译过来怎么就变了味呢?囧。。。)
Input:有一个长n米的木头,和一个price table,table如下:
长度 i 1 2 3 4 5 6 。。。
价格 Pi 1 5 8 9 10 17。。。
意思很明显,就是长度为1米的木头可以买1元,长5米的可以卖10元,依次类推
Output:找一个cut的方法,使最后赚的钱最多。
很显然,这个递归的主要思路是我切一刀之后,分成两段,一段我按table的价钱卖了,另一段我当成一个新的子问题,继续作为我的函数的新的参数,这样不就递归了吗?(__) 但是问题是这一刀怎么切,没错,我们就来个找最大值,即max_{i =1 to n} Pi + Cut(n-i).
所以,递归函数应该是:
Cut(P, n){ //P 就是我的table,n是木头长度
if n == 0
return 0;
q = -infinity
for i = 1 to n
q = max(q,P[i]+Cut(P,n-i))
return q;
}
然后,根据这个recursive写DP
Cut(P, n){
for(int i = 1; i<=n; i++){
q = -infinity;
for(int j = 1; j<=i; j++)
q = max(q, P[j] + r[i-j]);
r[i] = q;
}
return r[n];
}