区间dp求区间l,r的最优解的时候,要将l,r区间与区间外的元素独立开来,将l看成1 ,r看成n,然后将l,r的小区间合并,在合并的时候计算最优解; 特别要注意区间dp的初始化问题 线性dp是从左到右进行dp的,区间dp可以从任意位置进行dp
POJ 2955 Brackets
题意:给一个括号序列,问最多有多少个匹配的括号
思路:区间dp的模板题目,dp[l][r]表示区间l,r有多少个匹配的括号,当s[l]与s[r]匹配时 dp[l][r]=max(dp[l+1][r-1]+2);
然后按区间dp套路枚举断开点k dp[l][r]=max(dp[l][k]+dp[k+1][r])
POJ 1651 Multiplication Puzzle
题意:给你一串数字,从中任意拿出数字(不能拿第一个和最后一个数字),最后只剩下两个数字,求怎样使得所有拿出的数字和其两边的数字的乘积和最小,输出最小值
思路:板子 dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j] + card[i] * card[k] * card[j]);
LightOJ 1422 Halloween Costumes
题意:小灰灰要参加聚会,要穿聚会衣服,一件衣服如果脱了下来,就不能再穿上去,衣服可以套衣服,一件衣服如果在一次聚会中已经用过,没有脱下来,在下一次聚会还可以用这件衣服,现在按顺序参加n个聚会(从1开始),求小灰灰最少要买多少件衣服
思路:当a[l]==a[r]时,我们可以在r那个聚会用l聚会这个衣服(因为l是第一件衣服,肯定可以不用脱下来,可以在l衣服套其它衣服) 那么dp[l][r]=min(dp[l+1][r],dp[l][r-1]) 然后我们按区间dp模板枚举断点k dp[l][r]=min(dp[l][k]+dp[k+1][r]);
HDU 2476 String painter
题意:给二个字符串a,b;求a刷成b的最小次数,每刷一次可以将一段刷成一个字母
思路:直接计算将a刷成b比较复杂,可以先计算将一个空串刷成b,可以利用区间dp的方法,dp[l][r]表示将空串刷成b[l]~b[r]的最少次数;
有一个坑,很容易想到 当b[l]==b[r]时 dp[l][r]=dp[l+1][r-1]+1;这样是错误的,当b串为3个一样的字符时就会多算,正确的是
在枚举k的时候,判断 b[l]==b[k+1],当b[l]==b[k+1]时我们在合并区间 l,k k+1,r时就可以减1 ,因为我们可以一次就将l到k+1刷成一种字母 dp[l][r]=min(dp[l][k]+dp[k+1][r]-(b[l]==b[k+1])); 现在要计算出将a刷成b的最少次数令f[i]表示为a前i个字符刷成b前i个最少次数,f[i]初始值显然为dp[1][i] ,当a[i]==b[i]时,我们f[i]=f[i-1];当a[i]!=b[i]时,f[i]=min(f[j]+f[j+1][i]) 1<=j&&j<i;
HDU 4283 You Are the One
题意:给一个长度为n的序列,现在这n个数要按照从1到n要按照顺序入栈,假设第i个人,第k出栈,那么这个人的贡献为(k-1)*a[i],求n个人都出栈的贡献最小值
思路:我也不知道为什么这题用区间dp,难道是因为贡献和位置有关?? 单独考虑区间l,r 第l个人出栈可以是1到r-l+1(单独考虑) 假设他是第k个人出栈(1<=k&&k<=r-l+1)那么 第l+1到第l+k-1的人是l+1,l+k-1区间的最优解,因为在合并区间时并没有人出栈在他们前面,但是a[l]呢 本来是第一,现在有k-1个人在他前面,那么他的贡献因该是(k-1)*a[l] ,现在考虑后面的区间l+k,r;
现在有k个人排在这个区间的前面,那么这个区间的每个人贡献都要加k*a[x] ,可以用前缀和,那么贡献就是 k*sum这个区间,然后加上这个区间单独出栈的最优值 dp[l][r]=min(dp[l+1][l+k-1]+a[l]*(k-1)+dp[l+k][r]+k*(sum[r]-sum[l+k-1])).注意初始化dp数组;
ZOJ 3469 Food Delivery
题意:在一个x坐标上,有n户人家,坐标为xi,和一个饭店,坐标为x;现在,这个饭店要给街上的每户人家送饭,每户人家,在等待过程中每秒会产生一个烦躁值,现在那个饭店的外卖员要送饭,速度为1/v ,求产生的最小烦躁值;
思路:我也不知道为什么这题用区间dp,难道是因为贡献和位置有关?? 状态转移方程很好想
初始化dp[i][i][0]=dp[i][i][1]=abs(x-a[i].first)*sum[n];
int x1=sum[n]-sum[r]+sum[l];
int x2=sum[n]-sum[r-1]+sum[l-1];
dp[l][r][0]=min(dp[l][r][0],dp[l+1][r][0]+abs(a[l+1].first-a[l].first)*x1); dp[l][r][0]=min(dp[l][r][0],dp[l+1][r][1]+abs(a[r].first-a[l].first)*x1); dp[l][r][1]=min(dp[l][r][1],dp[l][r-1][0]+abs(a[r].first-a[l].first)*x2); dp[l][r][1]=min(dp[l][r][1],dp[l][r-1][1]+abs(a[r].first-a[r-1].first)*x2);
注意要将x坐标排序,题目保证输入输出不爆int ,但可能计算过程中爆int,所以在最后答案乘以v就行;
CodeForces 149D Coloring Brackets
题意:有一个匹配的括号序列,现在让你染色,有3个要求:a:每个符号必须染成 灰,绿,红三种颜色之一 b:相邻的二个符号不能都染成 绿色或者红色,但是可以染成灰色, c:一个匹配的括号 一定要有一个符号染成绿色或者红色
思路:我们用0表示灰色,1,2,表示其它二种颜色;这个题目状态比较多,用递归的形式写方便一点,有一个结论,假设l,r是一个匹配的括号序列,那么在l+1,r-1中不存在一个点使 l,k k+1,r 这二个区间是一个匹配的序列;而且我们要求的数量也是在匹配的区间找的;递归处理区间l,r ; 当区间长度为2时 (0,1)(0,2)(1,0)(2,0)(数字表示左右端点的颜色) 数量为1 其它数量为0;
当a[l]和a[r]匹配时,那么只能由区间(l+1,r-1)转移过来,递归处理区间(l+1,r-1)
当a[l]和a[r]不匹配时 那么区间l,r只能由 dp[l][match[l]] ,dp[match[l]][r] 这二个小区间转移过来,注意一下转移状态的条件即可;
HDU 5115 Dire Wolf
和poj1651一样
HDU 4632
题意:求一个字符串有多少个回文子序列,不同的子序列当且有一个字符位置不一样
思路: dp[l][r]表示区间l,r有多少个回文子序列,长度为1的子串初始化为1
dp[l][r]可以由 dp[l][r-1] dp[l+1][r]如果将他们相加会有一段重复 的,为dp[l+1][r-1]
当a[l]和a[r]相等时,dp[l][r]还可以由 dp[l+1][r-1]+1转移过来(+1为a[l]和a[r]也是一个回文;