区间dp(动态规划)

news2024/9/29 19:31:19

动态规划——区间dp

  • 什么是动态规划
    • 区间dp
      • 定义
      • 应用
  • 例题引入
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例
      • 样例输入
      • 样例输出
    • 提示
  • 贪心法
  • 区间dp
    • 优缺点:
    • AC代码:
    • 代码详解
      • 三层for循环
      • 状态转移方程
      • 环形的处理

在这里插入图片描述

什么是动态规划

动态规划(dp)是一种通过将问题分解为子问题,并利用已解决的子问题的解来求解原问题的方法。适用于具有重叠子问题和最优子结构性质的优化问题。通过定义状态和状态转移方程,动态规划可以在避免重复计算的同时找到问题的最优解,是一种高效的求解方法,常用于解决各种问题,如最短路径、背包问题、序列比对等。


区间dp

在这里插入图片描述

定义

区间dp是一种dp的应用,用于解决涉及区间的问题。
它将问题划分为若干个子区间,并通过定义状态和状态转移方程来求解每个子区间的最优解,最终得到整个区间的最优解。


应用

区间动态规划常用于解决一些涉及区间操作的问题,如最长公共子序列、最长回文子串等。在区间动态规划中,通常需要定义一个二维数组来表示子区间的状态,并通过填表的方式逐步求解子区间的最优解,最后得到整个区间的最优解。区间动态规划是一种高效的求解方法,可以有效地解决各种区间问题。



例题引入

石子合并是一道非常经典的区间DP的例题,很适合新手练习,下面我们看看这个题目:

题目描述

在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。

输入格式

数据的第 1 1 1 行是正整数 N N N,表示有 N N N 堆石子。

2 2 2 行有 N N N 个整数,第 i i i 个整数 a i a_i ai 表示第 i i i 堆石子的个数。

输出格式

输出共 2 2 2 行,第 1 1 1 行为最小得分,第 2 2 2 行为最大得分。

样例

样例输入

4
4 5 9 4

样例输出

43
54

提示

1 ≤ N ≤ 100 1\leq N\leq 100 1N100 0 ≤ a i ≤ 20 0\leq a_i\leq 20 0ai20



贪心法

稍微想想就知道不可行,因为它每次只能合并相邻的两堆石子,用贪心的话会答案错误,因此我们考虑区间dp。


区间dp

利用区间动态规划来解决此类问题。

优缺点:

优点缺点
可以求出正解时间复杂度高
代码量相对较少效率低
容易理解数据量大会超时
*** Sirius 你这缺点不都是同一个吗? 不不不,这不一样。 沉思了一小会 ??? *** Sirius

确实,此题的时间复杂度高达 O ( 2 n 3 ) O(2n^3) O(2n3),若非这道题的数据量极小,下面的代码便会超时,那么就需要用一个特殊方法来优化一下。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int n,ans1=0x7fffffff,ans2,a[300],sum[300];
int mi[300][300],ma[300][300];
int main() {
	cin >>n;
	for (int i=1; i<=n; i++) {
		cin >>a[i];
		a[i+n]=a[i];
	}
	for (int i=1; i<=2*n; i++)
		sum[i]=sum[i-1]+a[i];
	memset(mi,0x3f,sizeof(mi));
	for (int i=1; i<=2*n; i++)
		mi[i][i]=0;
	for (int l=1; l<n; l++) {
		for (int i=1; i+l<=2*n; i++) {
			for (int j=i; j<i+l; j++) {
				mi[i][i+l]=min(mi[i][i+l],mi[i][j]+mi[k+1][i+l]+sum[i+l]-sum[i-1]);
				ma[i][i+l]=max(ma[i][i+l],ma[i][j]+ma[k+1][i+l]+sum[i+l]-sum[i-1]);
			}
		}
	}
	for (int i=1; i<n; i++)
		ans1=min(ans1,mi[i][i+n-1]);
	for (int i=1; i<n; i++)
		ans2=max(ans2,ma[i][i+n-1]);
	cout <<ans1 <<endl <<ans2;
	return 0;
}

代码详解

三层for循环

  • 第一层for循环用来分区间,我们可以选择将一个大区间分成若干个小区间,那么分的标准是什么呢?这就是第一层for循环的作用, l l l就是每次分的区间长度。
  • 第二层循环就是定义区间的左端点, j = 1 j=1 j=1,再根据 l = 2 l=2 l=2,就能确定区间为 ( 1 , 2 ) (1,2) (1,2),即 f [ 1 ] [ 2 ] f[1][2] f[1][2]
  • 然后第三层循环就是拆分了,如上图, l = 2 l=2 l=2的时候是无法拆分了,但是 l = 3 l=3 l=3的时候是可以拆成 f [ 1 ] [ 2 ] , f [ 3 ] [ 3 ] , f [ 1 ] [ 1 ] , f [ 2 ] [ 3 ] f[1][2],f[3][3],f[1][1],f[2][3] f[1][2],f[3][3],f[1][1],f[2][3],以及各个数据都有或没有拆分方法。

状态转移方程

区间拆分了,那么我们如何去算转移方程呢?我们将两个区间 ( 1 , 2 ) (1,2) (1,2) ( 3 , 4 ) (3,4) (3,4)进行合并,那么就是1,2的代价加上3,4的代价,再加上1到4的区间和,具体的式子如下

f[1][4] = min(f[1][4],f[1][2]+f[3][4]+s[4]-s[0]);

为什么这么计算呢,因为你要知道你在求解的过程中是通过小的区间组合成较大的区间的,而你所用到的这两个小的区间 f [ 1 ] [ 2 ] + f [ 3 ] [ 4 ] f[1][2]+f[3][4] f[1][2]+f[3][4],已经得出了最优解了,那么得出最优解需不需要花费代价呢?当然需要,所以我们需要加上那段花费,那么简单来说就是

f[1][2]+f[3][4]=s[2]-s[0]+s[4]-s[2]

因此,状态转移方程便有了:

f[i][i+l]=min(f[i][i+l],f[i][k]+f[k+1][i+l]+s[i+l]-s[i-1]);

环形的处理

我们仔细阅读题目即可发现:石子是按照环形摆放的,因此区间的头和尾是能够合并的,那么如何处理呢?
方法很简单,只需要将整一条线性的石头复制一个,让第二个的头对着第一个的尾,然后正常处理即可。
这一点在程序的很多地方可以体现出来,如:

	for (int i=1; i<=n; i++) {
		cin >>a[i];
		a[i+n]=a[i];
	}

	for (int i=1; i<=2*n; i++)

以及

	for (int i=1; i+l<=2*n; i++)

等等。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

送你一个礼物——让学习科研工作从难题变乐趣

告诉你一个好消息&#xff0c;我的新书《学术写作五步法 —— 如何从零完成高质量论文》已于近期由人民邮电出版社出版上市。你可以在 京东 和 当当 等平台下单购买。 需求 科研新手往往会低估科研写作的难度&#xff0c;望文生义觉得科研成果无非就是「码字儿」而已。科研成果…

Postman 如何进行参数化

前言 Postman作为一款接口测试工具&#xff0c;受到了非常多的开发工程师的拥护。 那么做为测试&#xff0c;了解Postman这款工具就成了必要的了。 这篇文章就是为了解决Postman怎么进行参数化的。 全局变量 全局变量是将这个变量设置成整个程序的都可以用&#xff0c;不用去…

liunx下安装mysql5.7详细教程

1.下载mysql 可以直接去官网下载包&#xff0c;然后通过工具上传到服务器。 2.也可以直接用命令下载 默认下载当前所在位置 wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.42-linux-glibc2.12-x86_64.tar.gz -P 加文件夹路径&#xff0c;是将文件下载到指定…

OpenCV绘制矩形

这是完整的代码: #include <opencv2/opencv.hpp>int main() {// 创建一个白色的图像cv::Mat image(500, 500, CV_8UC3, cv

【机器学习核心总结】什么是神经网络

什么是神经网络 什么是神经网络&#xff1f;CNN、RNN、GNN&#xff0c;这么多的神经网络&#xff0c;有什么区别和联系&#xff1f; 既然我们的目标是打造人工智能&#xff0c;拥有智慧的大脑无疑是最好的模仿对象&#xff0c;人脑中有约860亿个神经元&#xff0c;这被认为是…

MySQL数据库总结 之 多表查询

一万两千字的博客&#xff0c;值的细细品味&#xff01; 更多关于MySQL的内容&#xff0c;请关注本帅哥的MySQL专栏&#xff01; 目录 1. 多表关系 1.1 一对多 1.2 多对多 1.3 一对一 2 多表查询 2.1 数据准备 2.2 概述 2.3 分类—内连接、外连接和自连接 3. 内连接 …

Openlayers Overlay基础及重点内容讲解

Overlay这个组件在Openlayers 项目中是经常要用到的,使用的场景通常是作为弹窗,显示某点或者某区域的信息。它不是根据屏幕位置固定的,而是与地理坐标相关联,因此平移地图将移动 Overlay。常用的大致有三类,弹窗、标注、文本信息。每个覆盖物都会生成对应的HTML元素,所以…

Ubuntu20.04安装后,root账户无法登录,ssh无法远程连接处理方法

最近一直在用Ubuntu系统&#xff0c;发现了一些规律性的东西&#xff0c;每当安装完系统就得去做一些事情&#xff0c;要不然无法正常丝滑的使用&#xff0c;我把这几个罗列出来&#xff1a;&#xff08;装机的步骤我就省了&#xff0c;比较简单跟着向导来就行&#xff0c;不要…

MySQL查询时指定使用索引

在MySQL中&#xff0c;可以通过指定查询使用的索引来提高查询性能和优化查询执行计划。以下是一些常见的场景&#xff0c;可能需要考虑指定查询使用的索引&#xff1a; 查询性能问题&#xff1a;当一个查询在大表上运行缓慢时&#xff0c;可以考虑为该查询指定合适的索引。通过…

计算机网络-运输层

目录 一、运输层概述 二、运输层端口号、复用和分用的概念 &#xff08;一&#xff09;端口号 &#xff08;二&#xff09;发送方的复用和接收方的分用 &#xff08;三&#xff09;TCP/IP体系的应用层常用协议所使用的运输层熟知端口号 三、UDP和TCP的区别 四、TCP的流量…

Modbus tcp转ETHERCAT在Modbus软件中的配置方法

Modbus tcp和ETHERCAT是两种不同的协议&#xff0c;这给工业生产带来了很大的麻烦&#xff0c;因为这两种设备之间无法通讯。但是&#xff0c;远创智控YC-ECT-TCP网关的出现&#xff0c;却为这个难题提供了解决方案。 YC-ECT-TCP网关能够连接到Modbus tcp总线和ETHERCAT总线中…

[论文笔记] Gemini: A Computation-Centric Distributed Graph Processing System

Gemini: A Computation-Centric Distributed Graph Processing System Gemini: 以计算为中心的分布式图处理系统 [Paper] [Slides] [Code] OSDI’16 摘要 提出了 Gemini, 一个分布式图处理系统, 应用了多种针对计算性能的优化以在效率之上构建可扩展性. Gemini 采用: 稀疏-…

99、基于STM32单片机智能指纹密码锁设计指纹识别控制门禁锁开关系统设计(程序+原理图+任务书+参考论文+开题报告+元器件清单等)

摘 要 近年来&#xff0c;指纹识别技术在国内外发展很快&#xff0c;由于其良好的安全性目前该技术已被广泛应用于生活和工作中。随着成本的下降&#xff0c;指纹识别技术呈现全面推广和普遍应用的趋势。 指纹识别技术是目前国际公认的应用广泛、价格低廉、易用性高的生物人…

6.Python:如何用Python进行数据可视化?

数据可视化是数据分析过程中不可或缺的一步&#xff0c;Python作为一个强大的编程语言&#xff0c;在数据可视化方面也是非常优秀的。本文将介绍使用Python进行数据可视化的基本步骤和常用工具。 一、Python数据可视化常用工具 Matplotlib Matplotlib是Python中最常用的数据…

git提交只单个或者某几个文件的指令

git status --查看目前本地和远程仓库的差异&#xff1b; git add --提交某的文件&#xff0c;多次执行可以提交多个文件 文件名称替换 git stash -u -k --其他文件保留到本地暂存区&#xff0c;不进行提交 git commit -m ---针对本次修改添加注释并提交到远程仓库 gi…

算法--辗转相除法

gcd 算法–辗转相除法 遇到一题算法题&#xff0c;如下&#xff1a; 求字符串的最大公因子&#xff1f; 对于字符串 s 和 t&#xff0c;只有在 s t … t&#xff08;t 自身连接 1 次或多次&#xff09;时&#xff0c;我们才认定 “t 能除尽 s”。 给定两个字符串 str1 和…

【LLM】金融大模型场景和大模型Lora微调实战

文章目录 一、金融大模型背景二、大模型的研究问题三、大模型技术路线四、LLaMA家族模型五、Lora模型微调的原理六、大模型Lora微调实战Reference 一、金融大模型背景 金融行业需要垂直领域LLM&#xff0c;因为存在金融安全和数据大多数存储在本地&#xff0c;在风控、精度、实…

Linux常用命令——expand命令

在线Linux命令查询工具 expand 将文件的制表符转换为空白字符 补充说明 expand命令用于将文件的制表符&#xff08;TAB&#xff09;转换为空白字符&#xff08;space&#xff09;&#xff0c;将结果显示到标准输出设备。 语法 expand(选项)(参数)选项 -t<数字>&am…

谷歌验证码kaptcha使用(包括前端获取解析)

1.后端 基于springboot开发。 包结构 1.导入依赖 <!--kaptcha验证码生成器--><dependency><groupId>com.github.axet</groupId><artifactId>kaptcha</artifactId><version>0.0.9</version></dependency> 2.配置类 …

企业低成本万能架构

企业软件应用架构层出不穷&#xff08;这里的应用架构是指偏后端服务的软件架构&#xff09;每个企业由各自业务形态&#xff0c;技术栈&#xff0c;技术路线&#xff0c;技术实力不同&#xff0c;各自架构方案&#xff0c;技术选型各有各的不同&#xff0c;千姿百态&#xff0…