区间dp——小结

一.定义:区间dp,就是先求小区间的最优解,然后逐步合并到大区间的最优解

二.代码实现大致步骤:

①找状态转移方程。f[i][j]一般是表示i~j区间的数字相加的最小代价。每次用变量k将其分成(i~k和k+1~j)两段

②区间dp的模板

for(int i=1;i<=n;i++)  
{  
    dp[i][i]=初始值  
}  
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=i;k

三.区间dp大致题型:

①:切木棍,问怎样切割有最小代价

uva 10003 - Cutting Sticks(区间DP)

设dp[i][j]表示从i到j的最小花费,那么dp[i][j]=min{dp[i]
[k]+dp[k][j]+a[j]-[i]}(i

②:将该字符串转成回文串的最小代价

poj 3280 Cheapest Palindrome(区间DP)

给出一个由n个小写字母组成的,长度为m的字符串字符串来,对这个字符串进行删除字母或者添加字母,使得该字符串是一个回文串,每一步删除和添加每个字母都有对应的代价,求将该字符串转成回文串的最小代价
对于一个串来说在一端删除一个字母和再另一端添加一个字母是一样的,所以对于每个字母来说,他的代价就是删除与添加的代价的较小值
dp[i][j]表示i到j是回文串的最小代价
if(s[i]==s[j])
         dp[i][j]=dp[i+1][j-1];
else
          dp[i][j]=min(dp[i+1][j]+w[s[i]-'a'],dp[i][j-1]+w[s[j]-'a']);
③:

POJ1651 Multiplication Puzzle

给你若干张卡片,第i张卡片的分值为Score[ i ] ( 1 <= i <= N )。现在游戏如下,给定N张卡片,除了第一张和最后一张卡片不可取之外,你可任取一张,得到分值Score[ i – 1] * Score[ i ] * Score[ i + 1 ],然后就把这张卡片去掉。题目要求最后计算最小的总得分。
把这道题倒过来看,每次向这个数列里面添加数的话,就会拿到这样的模型:首先向两个数a,c中间加上一个数b,然后剩下的数字只能加到a,b中间或者b,c中间,这样,就得到了一个动态规划的策略,转移方程为:dp[a][c] = dp[a][b] + dp[b][c] + s[a]*a[b]*s[c],如果在a和c中间遍历b,就可以得到dp[a][c]的值。

uva 1351 - String Compression

letsgogogo可以按照要求简写成lets3(go),简写后的长度是9,而原来的长度是10,问题所求的就是将给定的字符串简写后的最小长度是多少?
要注意可能简写后的长度比原来还要长,那么久要保留原来的长度,因为简写需要考虑3(go)这样的前边重复遍数的这个数字的位数,另一方面还要考虑需要在重复的子串两侧加上(),例如letsgogo,原来长度是8,按照要求简写后是lets2(go),长度是9,所以就要保留原来的长度
因为要求的是0-len-1这一区间的最小长度
设dp[i][j]表示i-j区间的最小长度
那么dp[0][len-1]即所求
dp[i][j]有两种状态,一种是来自于两部分的组合,即dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])
另一种就是来自于组合好的长度
 dp[i][j]=min(dp[i][j],digit(d/p)+dp[i][i+p-1]+2);
其中d是i-j的长度,p是重复子段的长度
⑤:

POJ 3186 Treats for the Cows

有一些食物,放在一个两端开口的仓库里,每天只能从两端选择一端取出一件食物,并且食物的价值是随着天数逐天递增,第i天的价值 本来价值*i,求n天取出食物所取得的最大价值;
状态转移方程:dp[i][j]=max(dp[i+1][j]+t[i]*(n-j+i), dp[i][j-1]+t[j]*(n-j+i));
i~j 看作 食物存放次序第 i 到 j  的一段区间
⑥:

poj 2955 Brackets

题意:给你一个只包括大小括号的串,一个合法串的定义如下:
1.空串是合法的;
2.若s为合法的,则 [s] (s) 也为合法的;
3.若 a,b为合法的 , ab 也是合法的。
给你一个长度小于100的串,求其所包含的的最长的合法串所包涵的字符数。

解法:经典区间dp,括号匹配问题,o(n3)

状态:dp[i][j] 表示 s[i]到s[j]字符区间内的最长长度。
转移方程:
if(s[i] 与 s[j] 匹配 ) --> dp[i][j] = max(dp[i+1][j-1]+2 , dp[i][k]+dp[k+1][j]);
else --> max(dp[i+1][j-1] , dp[i][k]+dp[k+1][j]);
初始化:
dp的边界便是区间长度为1的情况,并且这种情况下的答案是0,所以全部初始化为0即可。同时注意到转移是由区间长度由小到大来的,所以j的循环要改为由i-1递减得到。

zoj 3469 Food Delivery 

有一家快餐店送外卖,现在同时有n个家庭打进电话订购,送货员得以1/V的速度一家一家的运送,但是每一个家庭都有一个不开心的值,每分钟都会增加一倍,值达到一定程度,该家庭将不会再订购外卖了,现在为了以后有更多的家庭订购,要将外卖送到的情况下使得所有用户的不开心值总和达到最小
    很明显,每多走一分钟,没送到的家庭的不开心值都会加倍,
    假设是这样的顺序123X456,从X出发先往左右中间靠近的送,再往两边送省时间
        dp[i][j][0]表示从i到j用户送到最小不开心值,此时送货员停留在左边即i位置
        dp[i][j][1]表示从i到j用户送到最小不开心值,此时送货员停留在右边即j位置
    状态有四种,
     dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(a[i+1].x-a[i].x)*(delay+a[i].v));
     dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(a[j].x-a[i].x)*(delay+a[i].v));
     dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(a[j].x-a[i].x)*(delay+a[j].v));
     dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(a[j].x-a[j-1].x)*(delay+a[j].v));
⑧:

hdu-4745-Two Rabbits

两只兔子,在n块围成一个环形的石头上跳跃,每块石头有一个权值ai,一只从左往右跳,一只从右往左跳,每跳一次,两只兔子所在的石头的权值都要相等,在一圈内(各自不能超过各自的起点,也不能再次回到起点)它们最多能经过多少个石头(1 <= n <= 1000, 1 <= ai <= 1000)。
其实就是求一个环中,非连续最长回文子序列的长度。
dp[i][j] = max{ dp[i + 1][j], d[i][j - 1], (if a[i] == a[j]) dp[i + 1][j - 1] + 2 }
但是,这个dp公式仅仅是求出一个序列的非连续最长回文子序列,题目的序列是环状的,有两种思路:

将环倍增成链,求出窗口为n的最长子序列,但这不是最终的解,你可以试看看Sample 2,是只能得出4,因为它在选中的回文外面还可以选中一个当做起点来跳,所以外面得判断找出来的回文外面是否还有可以当起点的石头,即可以找窗口为(n-1)的长度+1。所以解即找 窗口为n的长度或者 窗口为(n-1)的长度+1 的最大值。

不倍增,直接当成一个链求dp,然后把链切成两半,求出两边的回文长度,最大的和就是解。这里不用考虑起点问题,因为两边的回文中点都可以做起点。

LightOJ 1422 Halloween Costumes

有N个宴会,对于每一个宴会,女猪脚都要穿一种礼服,礼服可以套着穿,但是脱了的不能再用,参加宴会必须按顺序来,从第一个到第N个,问参加这些宴会最少需要几件礼服,拿第一个案例来说把

4

1 2 1 2,有4个宴会,第一个需要礼服种类为1,第二个需要礼服种类为2,以此往下推:

参加第一个宴会时穿礼服1,参加第二个时,礼服1不要脱下,直接把礼服2套在外面,参加第三个的时候把礼服2脱下即可,参加第四个则需要一件新的礼服了

对于区间(i,j)如果第i件衣服和区间内的其他从i+1到j的衣服都不同,即第i件衣服在这个区间我们只穿一次,那么dp[i][j]=dp[i+1][j]+1;

否则遍历k(i

















你可能感兴趣的:(DP_区间dp)