区间dp入门——总结+习题+解析

前天学长拉了个区间dp的专题,花了两个做,今天就来做个总结吧!!!

区间dp其实就是一种建立在线性结构上的对区间的动态规划,dp本来就是很奇妙的东西,也没有什么套路,就是一种思考的数学思维方式,只有做足够多的题并且想的足够多才可能在比赛中做出来。

区间dp,顾名思义,在区间上dp,大多数题目的状态都是由区间(类似于dp[l][r]这种形式)构成的,就是我们可以把大区间转化成小区间来处理,然后对小区间处理后再回溯的求出大区间的值,主要的方法有两种,记忆化搜索和递推。

在用递推来求解时,关键在于递推是for循环里面的顺序,以及dp的关键:状态转移方程。

当然大部分的区间dp都是有特点的,我们可以考虑符合什么条件下,大区间可以转化成小区间,然后找出边界条件,进行dp求解。

区间dp也有很经典的板子部分,下面抛出代码和解析:

memset(dp,0,sizeof(dp))//初始dp数组
for(int len=2;len<=n;len++){//枚举区间长度
    for(int i=1;in) break;//符合条件的终点
        for(int k=i;k<=j;++k)//枚举最优分割点
            dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);//状态转移方程
    }
}
         
        
    

当然dp数组的维度和边界条件以及转移方程都是可变的,但是很多简单题都是这样可以做出来的,难题也都是情况更复杂了些,其最基本的思想还是不变的。

区间dp大部分的题目还有一种优化,因为我们很容易知道正常的区间dp时间复杂度为O(n^3)的,对于有的n是1000的,会超时

这时候就要用到一个经典的优化可以把它优化到:O(n^2),其实证明很难理解,但是大部分题都不会卡,因为dp已经很难了。

就算需要四边形优化,也就是多开一个数组s的事,在枚举最优分割点时,再缩小一下枚举范围,经典的用空间换时间的做法。

下面抛出基于四边形优化的代码。

for(int len=2;len<=n;len++){
    for(int i = 1;i<=n;i++){
	int j = i+len-1;
	if(j>n) break;
	for(int k = s[i][j-1];k<=s[i+1][j];k++){
	    if(dp[i][j]>dp[i][k]+dp[k+1][j]+w[i][j]){
		dp[i][j]=dp[i][k]+dp[k+1][j]+w[i][j];
		s[i][j]=k;
	    }
	}
    }
}

具体的证明过程可以参考这篇博文:戳我戳我

区间dp的知识点其实不多,最重要的还是在状态转移方程这一块,当然这里也有一些经典而且有意思的题目给大家。


先给出一些经典区间dp题型:石子合并,环型石子匹配,括号匹配问题,括号匹配变形,整数划分,最优三角形剖分,最优矩阵链乘。(最后两个题型在最后给出链接,kuangbin带你飞专题里面有)

然后就可以做一下比较有意思的题目,比如kuangbin带你飞区间dp专题,当然还有其他经典题型,以后再补。

kuangbin带你飞区间dp专题
zoj3537——最优三角剖分+凸包 题解
poj2955——括号匹配+区间dp经典题 题解
codeforce-149D——括号匹配染色+区间dp 题解
poj1651——最优矩阵链乘 题解
zoj3469——区间dp好题 题解
hdu4283——经典区间dp 题解
Lightoj1422——区间dp经典题 题解
hdu2476——经典区间dp 题解

 

你可能感兴趣的:(区间dp,算法学习总结)