当前位置: 首页 > ops >正文

区间 DP 详解

区间动态规划(Interval dynamic programming,即区间 DP)常用来解决一段区间内的最优解。

区间 DP 类似于其他 DP,由多个子区间的答案合并为一个大区间的答案。

一般是先求出最小子区间的答案(如 d p i , i dp_{i,i} dpi,i),然后逐步进行合并得到最终答案。

区间 DP 一般可分为两种情况:

  1. 子区间 [ l , r ] [l,r] [l,r] 向周围两端扩散,一般其时间复杂度为 O ( n 2 ) O(n^2) O(n2)

    典型例题:P2758 编辑距离。

    基本步骤:

    1. 枚举左端点 l l l
    2. 枚举右端点 r r r
    3. 根据状态转移方程计算从小区间转移到更大区间后的最优值。
  2. 多个小区间的答案合并为一个大区间,时间复杂度通常在 O ( n 3 ) O(n^3) O(n3) 及以上。

    典型例题:P1775 石子合并(弱化版)。
    基本步骤:

    1. 枚举长度 l e n len len
    2. 枚举左端点 l l l
    3. 计算出右端点 r r r r = l + l e n − 1 r=l+len-1 r=l+len1)。
    4. 枚举区间的分割点 k k k,根据状态转移方程计算合并区间后的最优值。

例题

例题1:P2758 编辑距离

d p i , j dp_{i,j} dpi,j 表示在区间 [ l , r ] [l,r] [l,r] 中将 a i a_i ai 转化为 b i b_i bi 所消耗的最小代价。

  • 如果 s l ≠ s r s_l\ne s_r sl=sr
    d p l , r = max ⁡ { d p i − 1 , j + 1 , d p i , j − 1 + 1 , d p i − 1 , j − 1 + 1 , d p l , r } dp_{l,r}=\max\{dp_{i-1,j}+1,dp_{i,j-1}+1,dp_{i-1,j-1}+1,dp_{l,r}\} dpl,r=max{dpi1,j+1,dpi,j1+1,dpi1j1+1,dpl,r}

    如果 s l = s r s_l=s_r sl=sr
    d p l , r = max ⁡ ( d p l , r , d p l − 1 , r − 1 ) dp_{l,r}=\max(dp_{l,r},dp_{l-1,r-1}) dpl,r=max(dpl,r,dpl1,r1)

实现
#include<bits/stdc++.h>
using namespace std;
string s,s1;
int dp[2005][2005];
int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>s>>s1;s=' '+s,s1=' '+s1;fill(dp[0],dp[2005],INT_MAX);for(int i=0;i<s.size();i++){dp[i][0]=i;}for(int j=0;j<s1.size();j++){dp[0][j]=j;}for(int i=1;i<s.size();i++){for(int j=1;j<s1.size();j++){dp[i][j]=min({dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+1,dp[i][j],(s[i]==s1[j]?dp[i-1][j-1]:INT_MAX)});}}cout<<dp[s.size()-1][s1.size()-1];return 0;
}

例题2:CF2074G Game With Triangles: Season 2

d p l , r dp_{l,r} dpl,r 表示在区间 [ l , r ] [l,r] [l,r] 范围的点能凑出来的最大价值。

由于图形是一个环,因此我们需要断环为链。

接下来枚举区间 [ l , r ] [l,r] [l,r],状态转移:

d p l , r = max ⁡ { d p l , r , d p l + 1 , k − 1 + d p k + 1 , r − 1 + a l × a k × a r , d p l , k − 1 + d p k , r , d p l , k + d p k + 1 , r } dp_{l,r}=\max\{dp_{l,r},dp_{l+1,k-1}+dp_{k+1,r-1}+a_l\times a_k\times a_r,dp_{l,k-1}+dp_{k,r},dp_{l,k}+dp_{k+1,r}\} dpl,r=max{dpl,r,dpl+1,k1+dpk+1,r1+al×ak×ar,dpl,k1+dpk,r,dpl,k+dpk+1,r}

最后,答案为 max ⁡ { d p i , i + n − 1 } \max\{dp_{i,i+n-1}\} max{dpi,i+n1}

实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t,n,a[805],dp[805][805];
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);for(cin>>t;t;t--){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];a[i+n]=a[i];}fill(dp[0],dp[n*2+1],0);for(int len=2;len<=n;len++){for(int l=1;l<=n*2-len+1;l++){int r=l+len-1;for(int k=l+1;k<r;k++){dp[l][r]=max({dp[l][r],dp[l+1][k-1]+dp[k+1][r-1]+a[l]*a[k]*a[r],dp[l][k-1]+dp[k][r],dp[l][k]+dp[k+1][r]});}}}int ans=0;for(int i=1;i<=n;i++){ans=max(ans,dp[i][i+n-1]);}cout<<ans<<'\n';}return 0;
}

例题3:P1775 石子合并(弱化版)

d p l , r dp_{l,r} dpl,r 表示 [ l , r ] [l,r] [l,r] 范围内的石堆合并的最小代价。

由于石头堆围成一个环所以需要断环为链。

预处理出前缀和数组 s u m sum sum

状态转移(要么维持原状,要么几堆石子合并在一块):

d p l , r = min ⁡ ( d p l , r , d p l , k + d p k + 1 , r + s u m r − s u m l − 1 ) dp_{l,r}=\min(dp_{l,r},dp_{l,k}+dp_{k+1,r}+sum_r-sum_{l-1}) dpl,r=min(dpl,r,dpl,k+dpk+1,r+sumrsuml1)

实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[305],sum[305],dp[305][305];
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n;fill(dp[0],dp[n+1],1e18);for(int i=1;i<=n;i++){cin>>a[i];sum[i]=sum[i-1]+a[i],dp[i][i]=0;}for(int len=2;len<=n;len++){for(int l=1;l<=n-len+1;l++){int r=l+len-1;for(int k=l;k<r;k++){dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1]);}}}cout<<dp[1][n];return 0;
}

例题4:P2858 [USACO06FEB] Treats for the Cows G/S

用区间 DP 计算最大收益。

要么拿左边那个( a l a_l al),要么拿右边的( a r a_r ar)。

因此可以推出状态转移:

d p l , r = max ⁡ ( d p l + 1 , r + a l × ( n − l e n + 1 ) , d p l , r − 1 + a r × ( n − l e n + 1 ) ) dp_{l,r}=\max(dp_{l+1,r}+a_l\times(n-len+1),dp_{l,r-1}+a_r\times(n-len+1)) dpl,r=max(dpl+1,r+al×(nlen+1),dpl,r1+ar×(nlen+1))

实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[2005],dp[2005][2005];
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n;for(int i=1;i<=n;i++){cin>>a[i];dp[i][i]=a[i]*n;}for(int len=2;len<=n;len++){for(int l=1;l<=n-len+1;l++){int r=l+len-1;dp[l][r]=max(dp[l+1][r]+a[l]*(n-len+1),dp[l][r-1]+a[r]*(n-len+1));}}cout<<dp[1][n];return 0; 
}
http://www.xdnf.cn/news/5231.html

相关文章:

  • Java注解:深入探究理解与实践应用
  • SpringMVC-简介及入门
  • linux中常用的命令(三)
  • Java MCP 实战 --> AI玩转贪吃蛇
  • BUCK基本原理学习总结-20250509
  • JVM调优
  • python tkinter 实现 带界面(GUI)的RSA加密、签名
  • Linux终端展示效果优化:【whiptail】使用教程
  • 【目录】学习如何使用dify建设专业知识库
  • 【AI提示词】金字塔模型应用专家
  • 3.优惠券秒杀
  • c++类【高潮】
  • MySQL开篇
  • C++Primerplus编程练习 第八章
  • 生产级AI/ML特征存储平台:Feast全面使用指南 — Use Cases Third party integrations FAQ
  • java: Compilation failed: internal java compiler error 报错解决方案
  • 【Java学习日记32】:面向对象,类和对象
  • matlab介绍while函数
  • 计算机网络:怎么理解WIFI穿墙?
  • SSRF服务端请求伪造
  • 2025python学习笔记
  • 用tinyb210实现srsran小基站
  • 全国青少年信息素养大赛 Python编程挑战赛初赛 内部集训模拟试卷六及详细答案解析
  • 2025年保安员考试题库及答案
  • 电影感户外哑光人像自拍摄影Lr调色预设,手机滤镜PS+Lightroom预设下载!
  • Linux进程间信号
  • 【25软考网工】第六章(2)信息加密技术
  • 【金仓数据库征文】金仓数据库(KingbaseES)迁移与集群部署实战:从MySQL到KES的全流程解析
  • 2003-2020年高铁线路信息数据
  • 为什么 AI 理解不了逻辑问题?