区间DP主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值,区间DP实际上就是经典DP的扩充内容,能从分割区间的思路上去解决问题。
一般区间DP实现代码::
memset(dp, 0x3f, sizeof(dp));//将dp区间初始化;
for (int i = 1; i <= n; i++) //区间长度为1的初始化;
dp[i][i] = 0;
for (int len = 2; len <= n; len++) //枚举区间长度;
{
for (int i = 1, j = len; j <= n; i++, j++) //区间[i,j];
{
动态转移方程;
}
}
第一类:区间合并最值问题 首先,排除特殊案例,一堆或两堆问题,一堆无花费,两堆花费为两堆之和;
其次,处理普通案例,多堆问题,由于只能对相邻的进行处理,因此肯定是将相临两个取小的值然后继续向后面进行重复的运算,对于经典dp肯定是一个个向后面加而区间dp则是先将画出一个个小的空间再将空间内的进行这样的运算,例如,讲过的石堆合并:
for (int len = 2; len <= n; len++)
{
for (int i = 1, j = len; j <= n; i++, j++)
{
for (int k = i; k < j; k++)
{
if(dp[i][j] > dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1])
dp[i][j] = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1];
}
}
}
就是将【i】【j】区间划分成【i】【k】和【k+1】【j】;
第二类:例如讲过的符号分割问题 就是将整个区间看成是【i-1】【j】后面加一个字符或者是【i+1】【j】前面加一个字符。
如果a[i+1]到a[j]没有和a[i]匹配的,
那么dp[i][j] = dp[i+1][j]
如果a[k]和a[i]匹配(i < k <= j),那么
dp[i][j] = max(dp[i][j], dp[i+1][k-1] + dp[k+1][j] + 2);
第三类:就是对区间的两个端点进行处理,不再对整个区间进行分析,而是通过对端点的操作来进行整体的目标的实现。
最后,谈一下我这段时间的看法吧,dp确实是比较好用的一种方法,尤其是dp延伸出的种种类型,能够解决不同方面的复杂问题,可以肯定的是,相比较于贪心算法来说解决的问题更多元化,我对于贪心来说感觉很好用,但是,贪心贪不好就会弄巧成拙,更多感觉是dp是对贪心贪不出来的问题的解决方式。