区间dp作为线性dp的一种,顾名思义是以区间作为阶段进行dp的,使用它的左右端点描述每个维度,决策往往是从小状态向大状态转移中推得的。它跟st表等树状结构有着相似的原理---向下划分,向上递推。

  dp最终要求的就是推出状态转移方程,从板子中我们可以感受出来区间dp的关键在于如何找到小状态与大状态的关系。

  

for(int i=;i<n;i++){//区间长度
for(int l=;l+i<=n;l++){//左端点
for(int h=l;h<l+i;h++)//枚举区间合并的分割点找到最优解
//转移方程
}
}

  这样基本的板子时间复杂度会达到o(n^3),如果被卡的话通常就要从四边形不等式等状态转移的性质出发能不能找到更好的转移,优化掉冗余。dp是拿空间换取时间的搜索,只要优化掉冗余推平不是梦。(蒟蒻口胡orz~)

  刷了一点蓝书上的例题,分享一下存个档

石子合并

传送门

非常经典的区间dp题,肉眼可见dp[l][r]=minrk=l(dp[l][r],dp[l][k]+dp[k+1][r])

#include<bits/stdc++.h>
using namespace std;
int dp[][];
int sum[];
int main()
{
int n;scanf("%d",&n);
memset(dp,0x3f,sizeof dp);
for(int i=;i<=n;i++)
scanf("%d",&dp[i][]),sum[i]=sum[i-]+dp[i][],dp[i][i]=;
for(int i=;i<n;i++){//区间长度
for(int l=;l+i<=n;l++){//左端点
for(int h=l;h<l+i;h++)//枚举区间合并的分割点找到最优解
dp[l][l+i]=min(dp[l][h]+dp[h+][l+i]+sum[l+i]-sum[l-],dp[l][l+i]);//转移方程
}
}
cout<<dp[][n]<<endl;
}

Polygon

传送门

枚举删掉的第一条边,就跟上一题类似了,由于存在乘,同时维护最大和最小的状态转移一下就OK啦

#include<bits/stdc++.h>
using namespace std;
char c[][];
long long dp[][][],num[];
vector <int> v,ans;
int main()
{
int n;scanf("%d",&n);getchar();
for(int i=;i<=*n;i++){
if(i&){
int t1=i/,t2=i/+;
if(t1==) t1=n;
scanf("%c",&c[t1][t2]);
c[t2][t1]=c[t1][t2];
}
else scanf("%lld",&num[i/]),getchar();
}
int tot=,mi=-1e9;
for(int i=;i<=n;i++){
v.clear();v.push_back();
for(int j=i;j<=n;j++)
v.push_back(j);
for(int j=;j<i;j++)
v.push_back(j);
for(int j=;j<=n;j++)
for(int h=;h<=n;h++)
dp[j][h][]=-1e18,dp[j][h][]=1e18;
for(int j=;j<=n;j++) dp[j][j][]=dp[j][j][]=num[v[j]];
for(int j=;j<n;j++){
for(int l=;l+j<=n;l++){
for(int k=l;k<l+j;k++){
long long t1=1e18,t2=-1e18;
if(c[v[k]][v[k+]]=='t')
t1=min(t1,dp[l][k][]+dp[k+][l+j][]),
t2=max(t2,dp[l][k][]+dp[k+][l+j][]);
else{
for(int p=;p<;p++)
for(int q=;q<;q++)
t1=min(t1,dp[l][k][p]*dp[k+][l+j][q]),
t2=max(t2,dp[l][k][p]*dp[k+][l+j][q]);
}
dp[l][l+j][]=max(dp[l][l+j][],t2);
dp[l][l+j][]=min(dp[l][l+j][],t1);
}
}
}
if(dp[][n][]>mi){
mi=dp[][n][];ans.clear();ans.push_back(tot);
}
else if(dp[][n][]==mi) ans.push_back(tot);
tot++;
}
cout<<mi<<endl;
int l=ans.size();
for(int i=;i<l;i++)
printf("%d%c",ans[i],i==l-?'\n':' ');
}

当然这个还有优化成o(n^3)的写法,对枚举删第一条进行优化。

金字塔

传送门

阅读题。。。dp[l][r]表示s[l]-s[r]的可以构成的个数,那么枚举k为第一个子树的分割点就可以得出

  dp[l][r]=Σdp[l][k-1]+dp[k][r-1]

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e2+;
const int mod=1e9;
char s[maxn];
int dp[maxn][maxn];
int main()
{
scanf("%s",s+);int n=strlen(s+);
for(int i=;i<=n;i++) dp[i][i]=;
for(int l=n-;l>=;l--)
for(int r=l+;r<=n;r++){
if(s[l]==s[r]){
for(int k=l+;k<r;k++)
dp[l][r]=(dp[l][r]+1LL*dp[l][k-]*dp[k][r-]%mod)%mod;
}
}
cout<<dp[][n]<<endl;
}

区间dp入门+例题的更多相关文章

  1. POJ 2955 Brackets (区间dp入门)

    Description We give the following inductive definition of a “regular brackets” sequence: the empty s ...

  2. 【DP】区间DP入门

    在开始之前我要感谢y总,是他精彩的讲解才让我对区间DP有较深的认识. 简介 一般是线性结构上的对区间进行求解最值,计数的动态规划.大致思路是枚举断点,然后对断点两边求取最优解,然后进行合并从而得解. ...

  3. hdu 4570 Multi-bit Trie 区间DP入门

    Multi-bit Trie 题意:将长度为n(n <= 64)的序列分成若干段,每段的数字个数不超过20,且每段的内存定义为段首的值乘以2^(段的长度):问这段序列总的内存最小为多少? 思路: ...

  4. POJ2955--Brackets 区间DP入门 括号匹配

    题意很简单,就是求给出串中最大的括号匹配数目.基础题,格式基本为简单区间dp模板. #include<iostream> #include<string.h> using na ...

  5. HRBUST - 1818 石子合并 区间dp入门

    有点理解了进阶指南上说的”阶段,状态和决策“ /* 区间dp的基础题: 以区间长度[2,n]为阶段,枚举该长度的区间,状态dp[l][r]表示合并区间[l,r]的最小费用 状态转移方程dp[l][r] ...

  6. 区间DP入门题目合集

      区间DP主要思想是先在小区间取得最优解,然后小区间合并时更新大区间的最优解.       基本代码: //mst(dp,0) 初始化DP数组 ;i<=n;i++) { dp[i][i]=初始 ...

  7. [nyoj737]石子归并(区间dp入门题)

    题意:有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值 ...

  8. 区间DP入门

    所为区间DP,主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值. 区间DP最关键的就是满足最优子结构以及无后效性!! 例如像是石子合并和括号匹配这两类比较经典的模型 ...

  9. poj 2955 区间dp入门题

    第一道自己做出来的区间dp题,兴奋ing,虽然说这题并不难. 从后向前考虑: 状态转移方程:dp[i][j]=dp[i+1][j](i<=j<len); dp[i][j]=Max(dp[i ...

随机推荐

  1. 035.集群安全-Pod安全

    一 Pod安全 1.1 PodSecurityPolicy启用 为了更精细地控制Pod对资源的使用方式,Kubernetes从1.4版本开始引入了PodSecurityPolicy资源对象对Pod的安 ...

  2. 《前端之路》- TypeScript (三) ES5 中实现继承、类以及原理

    目录 一.先讲讲 ES5 中构造函数(类)静态方法和多态 1-1 JS 中原型以及原型链 例子一 1-2 JS 中原型以及原型链中,我们常见的 constructor.prototype.**prot ...

  3. 《前端之路》- TypeScript (四) class 中各类属性、方法,抽象类、多态

    目录 一.TypeScript 中的类 二.TypeScript 中类的继承 三.TypeScript 中公共,私有与受保护的修饰符 3-1.属性的 public 3-2.属性的 private 3- ...

  4. Linux Ubuntu 开发环境配置 ——最具生产力工具一览

    Why Linux and Why exactly Ubuntu 首先这里就不做Mac,Linux,Windows三者之争了.只从个人角度分析下: Mac 不差钱(其实Mac作为超级本性价还行),不喜 ...

  5. 4 Values whose Sum is 0 POJ - 2785(二分应用)

    题意:输入一个数字n,代表有n行a,b,c,d,求a+b+c+d=0有多少组情况. 思路:先求出前两个数字的所有情况,装在一个数组里面,再去求后两个数字的时候二分查找第一个大于等于这个数的位置和第一个 ...

  6. 用pymysql和Flask搭建后端,响应前端POST和GET请求

    前言 这次作业不仅需要我建立一个数据库(详情请点击这里),还需要我基于这个数据库写后端接口(注册和登录)供前端访问,接收前端的POST和GET请求,并将登录.注册是否成功传给前端. 本文介绍如何用Fl ...

  7. ionic中select下拉框点击无反应解决办法

    两种解决办法: 1.在select外的div加入属性 data-tap-disabled=”true” 2.找到ionic.bundle.js文件 的下面这个函数,添加如图两行代码  

  8. 记一次Task抛异常,调用线程处理而引发的一些随想

    记一次Task抛异常,调用线程处理而引发的一些随想 多线程调用,任务线程抛出异常如何在另一个线程(调用线程)中捕获并进行处理的问题. 1.任务线程在任务线程执行语句上抛出异常. 例如: private ...

  9. CCF2018 12 2题,小明终于到家了

    最近在愁着备考,拿CCF刷题,就遇到这个难题,最后搜索了一下大佬们的方法,终于解决, 问题描述 一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间.同时,小明通过学校里安装 ...

  10. 深入解读ES6系列(四)

    来自老曾es6的前言: 哈喽小伙伴们,爱说'废'话的Z又回来了,欢迎来到Super IT曾的博客时间,上一节说了字符串,面向对象以及json的知识,这一节我们继续我们知识的海洋,一起奋斗不秃头!不足的 ...