区间DP入门
所为区间DP,主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值。
区间DP最关键的就是满足最优子结构以及无后效性!!
例如像是石子合并和括号匹配这两类比较经典的模型。
一般的区间dp写法是:
- for(int len=;len<=n;len++) //枚举区间长度
- {
- for(int i=;i<=(n<<)-len+;i++) //区间的左端点
- {
- int j=i+len-;
- for(int s=i;s<j;s++)
- {
- //大区间与小区间的关系;
- }
- }
- }
转移方程的推理:
首先,要计算合并的最大值、最小值,既然是动态规划,我们需要洞悉其中一些关联且确定的状态。
以下以最大值为例。
既然是最大值,那么求得的结果是否满足每一区间都是该区间所能达得到的的最大值?
显然是这样的。反证法:倘若有一个区间不是,那么换做该区间取得最大值的方案,最终结果将比原得分大。显然必定满足任意区间得分一定是该区间内的最大值。
这样我们可以定义状态f[i][j],表示i到j合并后的最大得分。其中1<=i<=j<=N。
既然这样,我们就需要将这一圈石子分割。很显然,我们需要枚举一个k,来作为这一圈石子的分割线。
这样我们就能得到状态转移方程:
$f[i][j] = max(f[i][k] + f[k+1][j] + d(i,j))$ 其中,1<=i<=<=k<j<=N。
d(i,j)表示从i到j石子个数的和,也就是合并的代价。
需要确定首尾指针,和枚举中间的断点,时间复杂度O(n3),虽然可以进一步利用什么四边形优化,在这里不做过探讨。
对于最简单的石子合并(成链状)来说,就是一个模板题,答案自然是dp[1][n]。
而对于呈环状的的来说则需要将数据复制一遍,答案为$max(dp[ i =(1-n) ][ i+n-1 ])$
- #include <algorithm>
- #include <iostream>
- #include <cstring>
- #include <cstdio>
- #include <vector>
- #include <queue>
- #include <map>
- using namespace std;
- #define LL long long
- #define mod int(1e9+7)
- #define wlz 1234567890
- int n,ans1,ans2;
- int a[],sum[],f1[][],f2[][];
- int main()
- {
- scanf("%d",&n);
- for(int i=;i<=n;i++)
- {
- scanf("%d",&a[i]);
- a[i+n]=a[i];
- }
- for(int i=;i<=n*;i++)
- {
- sum[i]=sum[i-]+a[i];
- f1[i][i]=f2[i][i]=;
- }
- for(int len=;len<=n;len++)
- {
- for(int i=;i<=(n<<)-len+;i++)
- {
- int j=i+len-;
- f1[i][j]=wlz;
- for(int s=i;s<j;s++)
- {
- f1[i][j]=min(f1[i][j],f1[i][s]+f1[s+][j]);
- f2[i][j]=max(f2[i][j],f2[i][s]+f2[s+][j]);
- }
- f1[i][j]+=(sum[j]-sum[i-]);
- f2[i][j]+=(sum[j]-sum[i-]);
- }
- }
- ans1=wlz;
- for(int i=;i<=n;i++)
- {
- ans1=min(ans1,f1[i][i+n-]);
- ans2=max(ans2,f2[i][i+n-]);
- }
- printf("%d\n%d",ans1,ans2);
- }
放上环状代码
对于括号匹配这一类。
给一个括号组成的字符串,问最多能匹配多少个括号
我们可以把[i,j]区间的字符当成由[i+1,j]在前面加个字符或[i,j-1]在后面加一个字符得来的
这里我们只考虑[i,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);
比如:[xxxxx]yyyyy通过括号分成两个子串
第二种模型就是根据匹配信息把区间划分成[i+1,k-1]和[k+1,j]
- while (gets(a+))
- {
- if(a[] == 'e') break;
- memset(dp, , sizeof(dp));
- int n = strlen(a+);
- for (int len = ; len <= n; len++)
- {
- for(int i = , j = len; j <= n; i++, j++)
- {
- dp[i][j] = dp[i+][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+][k-] + dp[k+][j] + );
- }
- }
- printf("%d\n",dp[][n]);
- }
代码还可以这样写
还有一类只需要枚举左右边界,比较简单,就不展开讲了。
区间DP入门的更多相关文章
- POJ 2955 Brackets (区间dp入门)
Description We give the following inductive definition of a “regular brackets” sequence: the empty s ...
- hdu 4570 Multi-bit Trie 区间DP入门
Multi-bit Trie 题意:将长度为n(n <= 64)的序列分成若干段,每段的数字个数不超过20,且每段的内存定义为段首的值乘以2^(段的长度):问这段序列总的内存最小为多少? 思路: ...
- POJ2955--Brackets 区间DP入门 括号匹配
题意很简单,就是求给出串中最大的括号匹配数目.基础题,格式基本为简单区间dp模板. #include<iostream> #include<string.h> using na ...
- HRBUST - 1818 石子合并 区间dp入门
有点理解了进阶指南上说的”阶段,状态和决策“ /* 区间dp的基础题: 以区间长度[2,n]为阶段,枚举该长度的区间,状态dp[l][r]表示合并区间[l,r]的最小费用 状态转移方程dp[l][r] ...
- 区间DP入门题目合集
区间DP主要思想是先在小区间取得最优解,然后小区间合并时更新大区间的最优解. 基本代码: //mst(dp,0) 初始化DP数组 ;i<=n;i++) { dp[i][i]=初始 ...
- [nyoj737]石子归并(区间dp入门题)
题意:有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值 ...
- poj 2955 区间dp入门题
第一道自己做出来的区间dp题,兴奋ing,虽然说这题并不难. 从后向前考虑: 状态转移方程:dp[i][j]=dp[i+1][j](i<=j<len); dp[i][j]=Max(dp[i ...
- LightOJ 1422:Halloween Costumes(区间DP入门)
http://lightoj.com/volume_showproblem.php?problem=1422 题意:去参加派对,有n场派对,每场派对要穿第wi种衣服,可以选择外面套一件,也可以选择脱掉 ...
- NYOJ 石子合并(一) 区间dp入门级别
描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价 ...
随机推荐
- C++经典面试题库 附带参考答案
1. 面向对象的程序设计思想是什么? 答:把数据结构和对数据结构进行操作的方法封装形成一个个的对象. 2. 什么是类? 答:把一些具有共性的对象归类后形成一个集合,也就是所谓的类. 3. ...
- P5165 xtq的棋盘
传送门 设\(f[i]\)为\(i\)位置向左走一步的期望时间,那么答案就是\(\sum_{i=1}^mf[i]\) 首先\(f[n]=1\),设\(p\)为向左的概率,对于\(i<n\)的位置 ...
- Luogu P1736 创意吃鱼法【dp】By cellur925
题目传送门 题意:给出一个01矩阵,找出一条对角线,使得对角线上的元素都为1,而对角线所在矩阵其他元素均为0,使得这样的对角线最长. 状态:$f[i][j]$表示以($i$,$j$)为对角线端点的最长 ...
- C#拷贝整个文件夹以及子目录和其中文件
private void CopyDirectory(string srcPath, string desPath) { string folderNam ...
- 限制属性绑定(__slots__)
正常情况下,当定义了一个class并创建实例后,可以给该实例绑定任何属性和方法,这就是动态语言的灵活性 属性和方法是可以直接定义在class中的,但动态绑定允许在程序运行的过程中动态给class加上属 ...
- Baker Vai LightOJ - 1071
题意:类似传纸条 方法: 把他要求的操作(一个人来回),转化为两个人同时走,除了开始和结束位置只能走不同路,得到的分数和的最大值即可. 一开始想到要定义的状态,是两个人的x(行)和y(列)坐标.这样时 ...
- 019 [工具软件]窗体置顶 DeskPins
DeskPins:Windows下将任何窗体置顶的工具 官方主页:https://efotinis.neocities.org/deskpins/index.html 官方下载的是一个exe安装包,用 ...
- 在input标签里只能输入数字
<input type='text' onkeyup="(this.v=function(){this.value=this.value.replace(/[^0-9-]+/,''); ...
- SEO & HTML语义化
SEO SEO的概念:搜索引擎优化,常见的搜索引擎有百度.谷歌等.优化的话,就是通过我们的处理,使得我们的网站在搜索引擎下有一个理想的结果. SEO的目的:当用户在搜索引擎上搜索关键词的时候,看到我们 ...
- Java&Xml教程(十一)JAXB实现XML与Java对象转换
JAXB是Java Architecture for XML Binding的缩写,用于在Java类与XML之间建立映射,能够帮助开发者很方便的將XML和Java对象进行相互转换. 本文以一个简单的例 ...