区间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;
}

最新文章

  1. CentOS7下安装配置MariaDB
  2. iOS之中途修改类名
  3. [Noip2016]蚯蚓 D2 T2 队列
  4. maven exclusion 解决maven传递依赖中的版本冲突
  5. Android -- 关闭AsyncTask(异步任务)
  6. PHP数据库操作:使用ORM
  7. CSS2系列:外边距合并问题(margincollapse)
  8. paper 89:视频图像去模糊常用处理方法
  9. SSH配置私钥登陆服务器
  10. ltrace killed by SIGTRAP
  11. 图论(KM算法,脑洞题):HNOI 2014 画框(frame)
  12. QWidget: Must construct a QApplication before a QPaintDevice的问题
  13. android脚步---图片浏览
  14. 使用BigDecimal报的错
  15. Mongo 专题
  16. VLAN原理解释
  17. .net 获取远程访问的ip
  18. vue 需求 data中的数据之间的调用
  19. dotnet 命令
  20. css的再深入4(更新中&#183;&#183;&#183;)

热门文章

  1. [Alg] 文本匹配-单模匹配-KMP
  2. requests模块使用一
  3. Web中间件 - 常见漏洞总结
  4. ArrayList,HashSet,SortedSet之间的区别是什么?
  5. 【转】不怕难之BlockingQueue及其实现
  6. git 更换push 提交地址
  7. Spring Controller单例与线程安全那些事儿
  8. golang工具之present - 编写go特色的ppt
  9. 终极解决方案——sbt配置阿里镜像源,解决sbt下载慢,dump project structure from sbt耗时问题
  10. tcp/ip面试题