区间dp

区间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]也是一个回文;

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值