DP专题

DP,即动态规划。从高中学习编程以来,我就没有完整,认真地学习过它。可事实证明,出来混迟早是要还的。过去欠下的漏洞,从现在开始填补。

言归正传,在我看来,DP与递推贪心数学归纳法都有相似之处。它与递推一样,只关注上一步与下一步的关系,事实上,许多dp最后的代码实现就是通过递推来写。它又和贪心很像,都是只关注局部最优解。它又和数学归纳法极其类似:找到边界,确定两步之间的关系。根据此关系,即可推出任意一步的结果。(一己之见,欢迎dalao批评指正)

以下给出例题(https://vjudge.net/contest/269597),为压缩篇幅,不贴完整代码,只给状态转移方程。

A - To The Max

大意:给一个N*N的数字矩形,求和最大子矩形

此题为最大子段和的升级版,对于最大子段和,我们知道其状态转移方程为:

dp[i]=max \left \{ dp[i-1],0 \right \}+a[i]

事实上,我们只需先把上下两行确定,求出范围内每一列的和(即把矩阵压缩为一维数组),就可以把问题转化为求最大子段和。

每一列之和可以在输入时即预处理好。

B - Maximum sum

大意:求最大的两段子段和

分两种情况。对于以i结尾的这个状态,若只有一个子段,公式与最大子段和相同;若有两个子段,则先找到之前所有的单个子段中最大的那一个,比较它与以(i-1)结尾的,两个子段的大小,取较大的那一个,再加上a[i]自己

dp[i][0]=max\left \{ dp[i-1][0],0 \right \}+a[i]

dp[i][1]=max\left \{ dp[i-1][1],max\left ( dp[1\rightarrow i][0] \right ) \right \}+a[i]

C - 最少拦截系统(导弹拦截)

大意:此题原题有两问,第一问:求最长不上升子序列;第二问:求拦截所有导弹,最少需要多少套系统。此题只截取了第二问。

对于第一问,很简单

dp[i]=max\left \{ dp[j] | j<i \cap a[j]>a[i] \right \}+1

第二问怎么求呢?有些人用dp+二分。但事实上,第二问就是在求最长上升子序列,证明如下

1)假设打导弹的方法是这样的:取任意一个导弹,从这个导弹开始将能打的导弹全部打完。而这些导弹全部记为为同一组,再在没打下来的导弹中任选一个重复上述步骤,直到打完所有导弹。

(2)假设我们得到了最小划分的K组导弹,从第a(1<=a<=K)组导弹中任取一个导弹,必定可以从a+1组中找到一个导弹的高度比这个导弹高(因为假如找不到,那么它就是比a+1组中任意一个导更高,在打第a组时应该会把a+1组所有导弹一起打下而不是另归为第a+1组),同样从a+1组到a+2组也是如此。那么就可以从前往后在每一组导弹中找一个更高的连起来,连成一条上升子序列,其长度即为K;

(3)设最长上升子序列长度为P,则有K<=P;又因为最长上升子序列中任意两个不在同一组内(否则不满足单调不升),则有

P>=K,所以K=P。

所以......把第一问的符号改一下就好啦

D - Brackets sequence

大意:括号匹配加强版。给了一个括号序列(只有"("  ")"  "["  "]") 现在让添加括号,使括号序列变得匹配,要求添加最少的括号,且输出这个匹配的括号序列。

区间DP。dp[i][j]表示区间i~j匹配添加括号后区间最小长度

dp[i][j]=dp[i][k]+dp[k+1][j]

注意当s[i]=='('&&s[j]==')' || s[i]=='['&&s[j]==']' 时,特判一下dp[i][j]=min(dp[i][j],dp[i+1][j-1]+2),这样可以找出匹配后的序列最小长度,但是题目要求输出匹配的序列,那么可以在定义一个数组v[i][j] 标记i~j区间的断开位置,如果s[i]=='('&&s[j]==')' || s[i]=='['&&s[j]==']' 时 v[i][j]==-1, 然后在递归调用输出即可;

关于区间DP还不是很懂,等我再找一些题,下次开一篇新的博客专门写一下。

你可能感兴趣的:(DP专题)