区间 DP

news/2025/3/17 16:19:44/文章来源:https://www.cnblogs.com/ctzm/p/18777069

区间 DP

区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来有很大的关系。

令状态 \(f(i,j)\) 表示将下标位置 \(i\)\(j\) 的所有元素合并能获得的价值的最大值,那么 \(f(i,j)=\max\{f(i,k)+f(k+1,j)+cost\}\)\(cost\) 为将这两组元素合并起来的价值。

区间 DP 有以下特点:

  • 合并:即将两个或多个部分进行整合,当然也可以反过来;

  • 特征:能将问题分解为能两两合并的形式;

  • 求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值。

环的处理

断环为链,从任意位置将环拆解为一条链,并将这条链延长两倍。

新的链长度为 \(2n\) 且第 \(i\) 个元素与第 \(n+i\) 个元素相同;用动态规划求解后,取 \(f(1,n),f(2,n+1),…,f(n−1,2n−2)\) 中的最优值,即为最后的答案。


例题:[NOI1995] 石子合并(断环板题),[NOIP 2006 提高组] 能量项链,石子合并(弱化版)


这里把划分型 DP 单列出来,不属于区间 DP 的范畴,但题目容易让人想到区间 DP(因为是划分成若干区间),所以有些博客会把它放进区间 DP。本质上是一个特殊的 DP 型 trick。

动态规划 - 划分型

给定长度为N的序列或字符串,要求划分成若干段

  • 段数不限或指定K段
  • 每一段满足一定的性质

做法

  • 类似于序列型动态规划,但是通常要加上段数信息
  • 一般用 \(f[i][j]\) 记录前i个元素 (元素 \(1-i\)) 分成 \(j\) 段的性质,如最小代价。

题目一

有一段由A-Z组成的字母串信息被加密成数字串。加密方式为:A->1,B->2,...,Z->26。给定加密后的字符串S[0...N-1],问有多少中方式解密成字符串?

确定状态

  • 给定一个加密的字符串后,我们将其划分为若干段数字,每段数字可以解密成一个字母。
  • 对于长度为N的加密后的字符串,从最后一步来说,若按一个位数进行划分,则方式数等于字符串前N-1的方式数;若按两位数进行划分,则方式数等于字符串前N-2的方式数。
  • \(f[i]\)表示字符串\(s\)\(i\)个数字解密成字符的方式数。

状态转移

  • 字符串S前i个数字解密成字母的方式数 = 前i-1个数字解密成字母的方式数 + 前i-2个数字解密成字母的方式数。
  • \(f[i] = f[i-1] + f[i-2]\)
  • 需要判断\(s[i],s[i-1]s[i]\)能否被解释为一个字母

代码

#include<bits/stdc++.h>using namespace std;int f[105];int main()
{string s;cin >> s;f[0] = 1;int len = s.length();for(int i=1;i<=len;i++){// 1位if( s[i-1] >= '0' && s[i-1] <= '9'){f[i] += f[i-1];}// 多位时 考虑2位if(i>1){int num = (s[i-2] - '0')*10 + (s[i-1]-'0');// 防止出现 01 -> A 的情况if(num > 9 && num < 27){f[i] += f[i-2];}}}cout << f[len] << endl;return 0;
}

题目二

给定一个正整数。问最少可以将n分成几个完全平方数之和。

确定状态

  • 最后一步:关注的是最优策略中最后一个完全平方数\(j^2\).
  • 最优策略中\(n-j^2\)也一定被划分成最少的完全平方数之和
  • \(f[i]\):表示\(i\)最少能被划分成几个完全平方数之和

状态转移

  • \(f[i] = min\{ f[i-j^2]+1, j^2 <= i\}\)

代码

#include<bits/stdc++.h>using namespace std;int n,f[105];int main()
{cin >> n;f[0] = 0;for(int i=1;i<=n;i++){f[i] = 1e8;for(int j=1;j*j<=i;j++){f[i] = min(f[i],f[i-j*j]+1);}}cout << f[n] << endl;return 0;
}

题目三

给定一个字符串S[0...N-1]。要求将这些字符串划分成若干段,每一段都是一个回文串。求最少划分几次?

确定状态

  • 对于最后一个回文字符串\(S[j...N-1]\),我们只需要知道前\(j\)个字符串最少划分次数 + 1即可。
  • 也就是说,求\(S[0...N-1]\)最少可以划分几次只需要求出\(S[0...j]\)最少可以划分几次。
  • \(f[i]\)表示前\(i\)个字符最少可以划分为几个回文串。

状态转移

  • \(f[i] = min\{f[j] + 1 ,\&\& S[j...i-1]是回文串 \}\)
  • \(f[0] = 0\)
#include<bits/stdc++.h>using namespace std;string str;
int f[105];
// 判断回文字符串
bool isBack(int st,int ed){int i=st,j=ed;while(i<=j){if(str[i] != str[j]){return false;}i++;j--;}return true;
}int main()
{cin >> str;int len = str.length();f[0] = 0;for(int i=1;i<=len;i++){f[i] = 1e8;for(int j=0;j<i;j++){if(isBack(j,i-1)){f[i] = min(f[i],f[j] + 1);}}}// f[len]表示前len个字符最少可以划分多少个回文串// f[len]-1表示的就是划分次数cout << f[len] -1 << endl;return 0;
}

题目四

有N本书需要被抄写,第\(i\)本书有\(A[i]\)页,i=1,2,...,N。有K个抄写原,每个抄写员可以抄写连续的若干本书。每个抄写员的抄写速度都一样,均为一分钟一页。问最少需要多少时间抄写完所有的书?

确定状态

  • 如果一个抄写员抄写第\(i\)本到第\(j\)本书,则需要时间\(A[i]+A[i+1]+...+A[j]\).
  • 最后的抄写完成时间取决于耗时最长的那位抄写员。--- 木桶原理
  • 题目就转化为:找到一种分段方式,分成不超过K段,使得所有段的数字之和的最大值最小。
  • 最优策略的最后一步:抄写员K,抄写一段连续的书 \(j,j+1,...,N\)
  • 第K个抄写员需要的时间\(A[j] + A[j+1]+...+A[N]\)
  • 最后的最优策略中就需要知道前\(K-1\)人抄写\(j-1\)本书的最小时间花费。
  1. 因为整体工程的抄写耗时最长的抄写员可能是第K个抄写员 也可能是前面K-1位抄写员的其中一位。若抄写耗时最长的抄写员为第K个抄写员,则答案就是第K个抄写员的抄写耗时时长。
  2. 另一方面,要保证每段的数字之和的最大值最小,需要知道前K-1个人抄写前j-1本书的最小时间花费。
  • 原:求K个人最短需要多少时间抄写完前N本书?
  • 现: 求K-1个人最短需要多少时间抄写完前j-1本书
  • \(f[k][i]\):K个抄写员最少需要多少时间抄写完前\(i\)本书。

状态转移

  • \(f[k][i] = min\{ max\{f[k-1][j-1],sum = \sum_{j=1}^{i} A[j] \} ,j=1,2,...,i\}\)
  • \(f[k][i]\): k个抄写员最少需要多少时间抄写完前\(i\)本书
  • \(f[k-1][j-1]\): K-1个抄写员最少需要多少时间抄写\(j-1\)本书
  • \(A[j] + ... + A[i]\):第k个抄写员抄写完第\(j\)至第\(i\)本书的时间
  • \(f[0][i] = MAX\): 0个抄写员抄写i本书的时间花费为无穷大,因为无法完成抄写
  • \(f[k][0] = 0\):K个抄写员抄写0本书的时间花费为0

代码

#include<bits/stdc++.h>using namespace std;int N,K,a[105],f[105][105];int main()
{cin >> N >> K;for(int i=1;i<=N;i++){cin >> a[i];f[0][i] = 1e8;}for(int k=1;k<=K;k++){f[k][0] = 0;for(int i=1;i<=N;i++){f[k][i] = 1e8;int sum = 0;// 抄写 j到i本书的最小花费,j = 1,...,ifor(int j=i+1;j>=1;j--){f[k][i] = min(f[k][i],max(f[k-1][j-1],sum));sum += a[j-1];}}}cout << f[K][N] << endl;return 0;
}

总结

  • 划分型动态规划一般要求将一个序列或字符串划分成若干满足要求的片段。
  • 解决方法:最后一步 ---> 最后一段,枚举最后一段的起点
  • 如果题目不指定段数,用\(f[i]\)表示前\(i\)个元素分段后的可行性/最值,方式数等
  • 如果题目指定段数,用\(f[i][j]\)表示前\(i\)个元素分成\(j\)段后的可行性/最值,方式数等

例题:[IOI 2000] 邮局,[POI 1999] 地图(其实是邮局的双倍经验)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/900427.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[ SpringMVC ] SpringMVC如何通过是否有@RestController注解来判断返回ModelAndView还是Json

引言之前在面试的遇到面试官问我SpringMVC的执行流程,我那时候回答的是SpringMVC的DispatcherServlet的dodispatch方法找到ControllerMethod之后将返回值通过convert成Json返回响应体,事后想了一下回答的其实并不正确,因为SpringMVC之前学习的时候有使用ModelAndView返回视图,我…

从HR+AI到AI+HR,企业人力资源AI进程已过半

一、人力资源管理智能化应势而上,核心价值受企业管理层肯定 过往各项研究表明,AI 已经被广泛应用于企业经营的各个环节中。根据易路于2023 年发布的《AI 在企业人力资源中的应用白皮书1.0》(以下简称《白皮书1.0》),我们可以明确感受到:AI 已不同程度应用于招聘管理、员工…

multi-object tracking in the dark

创新点:构建LMOT数据集:开发了一种双摄像头系统,同步采集明暗视频帧,形成高度对齐的低光视频对,并提供高质量的多目标跟踪标注。该数据集包含大量城市户外场景视频,涵盖多种动态物体,为模型训练和评估提供了丰富的数据支持。 提出LTrack方法:引入自适应低通下采样模块(…

LGP11831_1 [UPTS 2025] 追忆 学习笔记

LGP11831_1 [UPTS 2025] 追忆 学习笔记 Luogu Link 前言 又幻想了……唉! 幻想自己场切这道题,最后标准分上升至 \(\text{598pts}\),翻掉了 \(\text{yyz}\),不至于一点脸不要。 本题解基本借鉴这篇题解。 题意简述 给定一个 \(n\) 点 \(m\) 边的简单有向图 \(G\),有 \(m\)…

sql 在两个数据表中,A表存在字段以逗号分隔存储B表的多id对象,进行关联查询

A 表:B表:关联查询 需求为,查询出A表的数据列表,需要将A表关联B表的数据id,概要通过B表的 name 进行输出显示 SELECT A.id,A.name,A.creator,A.created_at,GROUP_CONCAT(B.name SEPARATOR , ) AS B_names -- 将 c_name 合并为逗号分隔的字符串 FROM xf_service_type A LE…

算力市场何以拥有巨大潜力

算力市场未来确实具有巨大的潜力,这一判断基于多个方面的因素: 一、算力成为经济增长的主要驱动力 随着全球数字化转型的迅猛推进,算力已成为推动经济增长的关键引擎。各国纷纷加大在算力基础设施方面的投入,以期为经济发展注入新的活力。例如,欧盟委员会批准了一项名为“…

算法备案拟公示内容编写指南

除了自评估报告,算法备案复审中的拟公示内容也是难度颇大的一份材料,导致很多开发者的算法备案申请被驳回。今天我就提供一份简易模板供大家学习参考(请结合实际情况撰写,不要照抄,不要买模板,否则会判定真实性存疑或高度雷同,影响备案)。(各类文件套模板都会判定该真…

CH585 RF_Basic例程讲解含单向和双向发送

CH585_RF基础通讯例程见下图路径:1、RF初始化参数配置/******************************************************************************** @fn RFRole_Init** @brief RF应用层初始化** @param None.** @return None.*/ void RFRole_Init(void) {rfTaskID = TMOS_…

uniapp整合SQLite(Android)

一、勾选SQLite数据库选项 (1)HBuilder工具打开项目 (2)项目/manifest.json =>App模块配置 => 勾选SQLite(数据库)二、封装sqlite.ts 在项目根目录下创建sqlite/sqlite.ts// 数据库名称 const dbName = scan/*** 数据库地址* @type {String} 推荐以下划线为开头 _d…

No.68 Vue---vue3新特性

一、vue3新特性 1.1 六大亮点二、组合API(setup)2.1 ref或者reactive 1、创建项目 vue create vue-demo5 2、进入文件,启动服务。 3、 2.2 methods中定义的方法写在setup() 2.3setup()中使用props和context 在2.x中,组件的方法中可以通过this获取到当前组件的实例,并执…

2025年2月国产数据库大事记-墨天轮

​本文为墨天轮社区整理的2025年2月国产数据库大事件和重要产品发布消息,一起看看2月有哪些大事发生~本文为墨天轮社区整理的2025年2月国产数据库大事件和重要产品发布消息。 目录2025年2月国产数据库大事记 TOP10 2025年2月国产数据库大事记(时间线) 产品/版本发布 兼容认证…