几个动态规划的常见例题

原贴地址:http://www.cnblogs.com/dmesg/archive/2009/07/31/1535772.html

1.LIS(Longest increase string)

( 3,-1,2,4,9,6)
LIS的考虑是当前点和前面最长递增子序列的最大值比较或者与次最长递增子序列的最大值比较或者与次次最长递增子序列的最大值比较。。。。。。这时的复杂度为O(n^2)。倘若用二分法查找这个“合适的最长递增子序列最大值”,复杂度可以降为O(nlogn)。


2. 最大子段和

这问题一般考虑有四种解法。第一种解法的复杂度为O(n^3),考虑为:一个控制头,一个控制尾,一个遍历操作。这是比较直观的考虑,很多问题都可以用这种方法来解。(比如最大子段积)

解法二的复杂度为O(n^2)。考虑从方法一而来。由于本体的特殊性(连续加是和),可以在控制尾的时候,同时进行遍历求值。

解法三是基于分治法的考虑。考虑到整个序列的最大和要不在左半段,要不在右半段,要不跨越左右半段。关键在于跨域部分的求解。可以分别求包含n/2的最大左半段和包含n+1/2的最大右半段和相加就可以了。
关于包含某值的特定方向的最大和,是容易求的。同时这个结论也是支撑方法四的核心。

解法四的复杂度是线性时间。对于这个问题,能想出线性解法的人,我们应该称之为神。一般的考虑是看前最大子段和i个元素的最大子段和与前i+1个的有什么联系,想了好长时间,原来没什么联系。
正确的解法是分别求包含i结点的前i个元素的最大子段和,这样的话,最大值总在其中。(遍历i时)
废话少说,看转移方程:
b[i]意思是前i个元素的最大子段和(包含i结点)
如果b[i-1]>0    b[i]=b[i-1]+arry[i]
如果b[i-1]<=0   b[i]= arry[i]

3. LCS
经典之中的经典问题,基本上每本算法书上的DP章节都拿来作镇山之宝。
初观此题,我简直不敢相信能够求解,当看到复杂度如此低而又直观的解法,直接拜地叹服。
略去废话,看状态转移方程
                 0            (i=0,j=0)
Dp(i,j)=    dp(i-1,j-1)+1    (i,j>0;Xi=Yj)
               Max{ dp(i,j-1) , dp(i-1,j)}  ( i,j>0;Xi!=Y)



4.  01背包问题

01背包是i问题和i+1问题间的联系,那么毋庸我废话,状态方程就可以表示一切了。
     背包的容量为j,可选择的物品为i,i+1,….n时    
     Dp(i,j)=   Max{ dp(i+1,j) , dp(i+1,j-w[i])+v[i] }  (j>=w[i]) 
                   dp(i+1,j)   (0
     

5.   数组分割问题
有个没有排序,元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个字数组的和最接近?
解:假设S=(a[1]+a[2]+...+a[n]+a[n+1]+...+a[2n])/2, 
那么这是个和0-1背包类似的动态规划问题,区别之处就是取的个数受到限制,必须得取足n个元素。

用dp(i,j,c)来表示从前i个元素中取j个、且这j个元素之和不超过c的最佳(大)方案,在这里i>=j,c <=S 
状态转移方程: 
dp(i,j,c)=max{dp(i-1,j-1,c-a[i]),dp(i-1,j,c)} 
dp(2n,n,S)就是题目的解。

你可能感兴趣的:(数据结构/算法)