一、区间DP

顾名思义区间DP就是在区间上进行动态规划,先求出一段区间上的最优解,在合并成整个大区间的最优解,方法主要有记忆化搜素递归的形式。

顺便提一下动态规划的成立条件是满足最优子结构无后效性

二、经典例题分析:

1.石子合并:

一条直线上有N堆石子,现在要将所有石子合并成一堆,每次只能合并相邻的两堆,合并花费为新合成的一堆石子的数量,求最小花费。

分析

一般看到最小,最短这样的字眼,可以往动态规划的方向思考,显然当我任选两堆合并时,只会影响下一次选择,不会对再后来的选择有影响,这时候我们几乎可以确认用DP了

1堆:花费为0.

2堆:花费为sum[2].

3堆:花费为min(a[1]+a[2],a[2]+a[3])+sum[3].

如果我们有N堆,最后一次合并一定是将两堆合并成一堆,那两堆一定都是最少花费,由此往下想:那两堆肯定也是有最优的两堆合并,这样就是一个递归过程。

所以我们可以想办法找出每个区间划分为两个最少花费区间的点,这就是第一个模型:

第一个模型:将大区间划分为两个小区间。

此题我们规定dp[i][j]为合并第i堆到第j堆的最小花费。

DP方程为:dp[i][j]=min(dp[i][k]+dp[k+1][j])+sum[j]-sum[i-1].

memset(dp,Ox3f,sizeof(dp))
for(int i=1;i<=dp.size();i++){
dp[i][i]=0;//将一堆石子合并花费为0
sum[i][i]=stones[i];//合并第i堆到第j堆的花费。
}
for(int len=1;len<n;len++){//区间长度
for(int i=1;i<=n&&i+len<=n;i++{//区间起点
int j=i+len;//区间终点
for(int k=i;k<=j;k++){//区间划分点
sum[i][j]=sum[i][k]+sum[k][j];
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j];
}
}
}

我们再看回 LeetCode合并石子:

与例题不同的是此题是给定一个K,要将K长度内的石子合并(我们知道石子是一行排列),换汤不换药,仍然是区间DP解法,只是将相邻两堆改成了相邻K堆:

本来我们只需将区间划分为任意两部分,如今我们要将区间这样划分:一部分长度为K-1,另一部分看作为一整堆,这样最后才能合并为一整堆,所以我们要做的改变只是将划分点每次移动的距离由1变为K-1,

保证左边部分为K-1的整数倍。

由此我们得出要有结果,stones长度必须满足:j-i%K-1==0。

int len=stones.length;
if((len-1)%(K-1)!=0)return -1;
int[][] dp=new int[len][len];
int[] sum=new int[len+1];
for(int i=0;i<len;i++){
dp[i][i]=stones[i];
sum[i+1]=sum[i]+stones[i];
}
for(int j=1;j<len;j++){
for(int i=j-1;i>=0;i--){//只需考虑能最后能求解的子区间,因为最后不会用到不能求解的
dp[i][j]=dp[i][i]+dp[i+1][j];//划分i,i+1-j两部分
for(int k=i+K-1;k<j;k+=K-1){
dp[i][j]=Math.min(dp[i][j],dp[i][k]+dp[k+1][j]);//DP方程:其中若i-j不是K-1的整数倍则继续DP时不会用到DP[i][j]。
}
if((j-i)%(K-1)==0){//最后合并。
dp[i][j]+=sum[j+1]-sum[i];
}
}
}
return dp[0][len-1]-sum[len];//每次小区间合并时都已计算合并时的花费所以需要减去。

这就是对第一模型的例题分析,都是将大区间划分为小区间,求取最优解。

2.括号匹配:

给定一个括号()[]组成的字符串,你要找到一个最长的合法的子序列,对于一个字序列,其中的括号一定有另一个相对应。

我们先尝试用上一模型解决试试:

规定dp[i][j]为第i个字符到第j个字符之间的最长匹配序列。

长度为N时,我们可以先检测a[i]和a[j]是否匹配,如果匹配,dp[i][j]=dp[i+1][j-1]+2,否则,就可以按第一模型处理,从任意位置划分为两个区间:dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j].

for (int len = 2; len <= n; len++)
{
for(int i = 1, j = len; j <= n; i++, j++)
{
if((a[i]=='('&&a[j]==')') || (a[i]=='['&&a[j]==']'))//i,j位置能匹配
dp[i][j] = dp[i+1][j-1] + 2;
for (int k = i; k < j; k++)//任意位置划分为两个区间
if(dp[i][j] < dp[i][k] + dp[k+1][j])
dp[i][j] = dp[i][k] + dp[k+1][j];
}

但这不是我们想要的第二个模型,假设我们只考虑[i,j]是由[i+1,j]在前面加一个字符的情况,如果a[i+1]到a[j]没有和a[i]匹配的,那么dp[i][j]=dp[i+1][j],如果匹配(i<k<=j),那么dp[i][j]=max(dp[i][j],dp[i+1][k-1]+dp[k+1][j]+2);

比如:[xxxxx]yyyyy通过括号分成两个子串.

所以第二种模型就是根据匹配信息把区间划分为[i+1,k-1]和[k+1,j]

for (int len = 2; len <= n; len++)
{
for(int i = 1, j = len; j <= n; i++, j++)
{
dp[i][j] = dp[i+1][j];//不能匹配
for (int k = i; k <= j; k++)//能匹配
if((a[i]=='('&&a[k]==')') || (a[i]=='['&&a[k]==']'))
dp[i][j] = max(dp[i][j], dp[i+1][k-1] + dp[k+1][j] + 2);
}
}

Cheapest Palindrome:

n个字符组成的长度为m的字符串,给出增删字符的花费,可在字符串的任意位置增删字符,求把字符串修改为回文串的最小花费。

例:n=3,m=4组成abcd,

a:1000,1000,b:350,700,c:200 800

这题分四种情况:假设有字符串:Xxxx...xxY

1.去掉X,取xx..xY回文;

2.去掉Y,取Xx...x回文;

3.在左边加上X,Xxx...xYX回文;

4.在右边加上Y,取YXxx...x回文;

规定dp[i][j]为把[i..j]区间改为回文串的最小花费

我们得出DP方程:dp[i][j]=min(dp[i][j],dp[i+1][j]+min(add[a[i]-'a']+sub[a[i]-'a'])),//增删X时

dp[i][j]=min(dp[i][j],dp[i][j-1]+min(add[a[i]-'a']+sub[a[i]-'a'])),//增删Y时

for (int len = 2; len <= m; len++)
for(int i = 1, j = len; j <= m; i++, j++)
{
dp[i][j] = min(dp[i][j], min(add[a[i]-'a'],sub[a[i]-'a']) + dp[i+1][j]);//增删X时
dp[i][j] = min(dp[i][j], dp[i][j-1] + min(add[a[j]-'a'],sub[a[j]-'a']));//增删Y时
if (a[i] == a[j])
{
if (len==2)
dp[i][j] = 0;
else
dp[i][j] = min(dp[i][j], dp[i+1][j-1]);//相等时就等于[[i+1..j-1]回文的长度。
}
}

这就是我们第三个模型只考虑左右边界,不需要枚举区间k->[i,j]

4.总结:

区间DP最重要的时理解大区间和小区间之间的联系,才能写出DP方程,其实也可以将其看成是一个递归过程大区间由小区间得出,小区间由小小区间得出。

区间DP(力扣1000.合并石头的最低成本)的更多相关文章

  1. Leetcode1000 合并石头的最低成本 区间DP

    有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头. 每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的总数. 找出把所有石头合并成一堆的最低成 ...

  2. [Swift]LeetCode1000. 合并石头的最低成本 | Minimum Cost to Merge Stones

    There are N piles of stones arranged in a row.  The i-th pile has stones[i] stones. A move consists ...

  3. [IOI1998] Polygon (区间dp,和石子合并很相似)

    题意: 给你一个多边形(可以看作n个顶点,n-1条边的图),每一条边上有一个符号(+号或者*号),这个多边形有n个顶点,每一个顶点有一个值 最初你可以把一条边删除掉,这个时候这就是一个n个顶点,n-2 ...

  4. 洛谷1880 区间dp+记忆化搜索 合并石子

    题目网址:https://www.luogu.com.cn/problem/P1880 题意是:给定一个序列,最小规则是相邻两个值的合并,开销是他们的和,将整个序列合并成一个值的情况下,求解该值的最小 ...

  5. 以石子合并为例的区间DP

    区间DP,是一类具有较为固定解法的DP,一般的思路都是: first.初始化区间长度为1的情况(一般区间长度为1的较易于初始化) second. for(枚举区间长度2~n){ for(枚举左端点){ ...

  6. 区间DP小结

    也写了好几天的区间DP了,这里稍微总结一下(感觉还是不怎么会啊!). 但是多多少少也有了点感悟: 一.在有了一点思路之后,一定要先确定好dp数组的含义,不要模糊不清地就去写状态转移方程. 二.还么想好 ...

  7. hdu 4283 区间dp

    You Are the One Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  8. cdoj 1131 男神的礼物 区间dp

    男神的礼物 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1131 Descr ...

  9. 洛谷P1040 加分二叉树(区间dp)

    P1040 加分二叉树 题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di, ...

随机推荐

  1. 虚拟机apache启动

    /usr/local/apache2/bin/apachectl restart 重启 当启动也行 尝试过进入目录运行,比较奇怪,www目录竟然不一致,直接使用 server httpd start ...

  2. Nginx笔记总结二十一:隐藏或者混淆nginx返回的Server信息

    [root@localhost nginx-]# vi src/http/ngx_http_header_filter_module.c 修改:49-50行 static char ngx_http_ ...

  3. Ubuntu16.04使用sublime text3编写C语言后,实现编译并自动调用bash终端运行程序

    实现编译并自动调用bash运行程序只需要新建自己的.build文件就OK 依次打开: tools->building system->new building system 后,把下面的内 ...

  4. PyTorch模型加载与保存的最佳实践

    一般来说PyTorch有两种保存和读取模型参数的方法.但这篇文章我记录了一种最佳实践,可以在加载模型时避免掉一些问题. 第一种方案是保存整个模型: 1 torch.save(model_object, ...

  5. php--0与空的判断

    使用empty()函数判断,两者都是true $a=0; if(trim($a)=="") { echo '数字0'; }

  6. Drools 7.15.0 docker容器方式部署

    关于drools的相关介绍就不再赘述了,关于drools网上的资料都很少,或者都有些老了,最近折腾了一下,记录下安装部署的过程,希望能节省下大家的时间. 一.快速部署 1.拉取基础镜像,命令如下: d ...

  7. Solr7.3.0入门教程,部署Solr到Tomcat,配置Solr中文分词器

    solr 基本介绍 Apache Solr (读音: SOLer) 是一个开源的搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.Apache ...

  8. 题解 P1951 【收费站_NOI导刊2009提高(2)】

    查看原题请戳这里 核心思路 题目让求最大费用的最小值,很显然这道题可以二分,于是我们可以二分花费的最大值. check函数 那么,我们该怎么写check函数呢? 我们可以删去费用大于mid的点以及与其 ...

  9. Inheritance Learning Note

    好几天没来学习了,昨晚把继承的又整理了一下.想把整理后的东西发到hexo博客上来,却发现命令行又失效了.前几天明明是好的,这几天又没有进行任何操作,网上搜了一下也没有招到合适的解决办法,无奈只能重装了 ...

  10. 两篇很好的EPG相关文章

    两篇很好的EPG相关文章 原文地址:http://blog.sina.com.cn/s/blog_53220cef0100pi8j.html 1 基于DVB-SI的数字有线电视机顶盒节目指南的设计实现 ...