算法刷题day52:区间DP

news2024/11/19 13:35:13

目录

  • 引言
  • 一、石子合并
  • 二、环形石子合并
  • 三、能量项链
  • 四、加分二叉树

引言

关于区间DP,我其实觉得核心思想就是把一个区间拆分为任意两个区间,相当于是模拟枚举全部这种区间组合的过程,然后从中寻求最优解,本质上的思想不难,难的是跟其它知识点的一个组合,只是说用到了这种思想而已,那这就有挑战性了,不过还是继续加油吧!


一、石子合并

标签:动态规划、区间DP

思路:整个区间 D P DP DP 的模板就是如下的一种形式,先枚举长度,然后枚举左端点,并且让右端点不能超过整个的区间,然后去进行区间的拆分,找到最优解。状态定义就是 f [ l ] [ r ] f[l][r] f[l][r] 代表合并 l ∼ r l \sim r lr 所花费的最小代价。

题目描述:

设有 N 堆石子排成一排,其编号为 1,2,3,…,N。

每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。

每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选
择的顺序不同,合并的总代价也不相同。

例如有 4 堆石子分别为 1 3 5 2, 我们可以先合并 1、2 堆,代价为 4,得到 4 5 2, 又合并 1、2 堆,代价为 9,得到 9 2 ,再合
并得到 11,总代价为 4+9+11=24;

如果第二步是先合并 2、3 堆,则代价为 7,得到 4 7,最后一次合并代价为 11,总代价为 4+7+11=22。

问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

输入格式
第一行一个数 N 表示石子的堆数 N。

第二行 N 个数,表示每堆石子的质量(均不超过 1000)。

输出格式
输出一个整数,表示最小代价。

数据范围
1≤N≤300
输入样例:
4
1 3 5 2
输出样例:
22

示例代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y second

const int N = 310, M = N, INF = 0x3f3f3f3f;

int n, m;
int s[N], f[N][N];

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> s[i], s[i] += s[i-1];
	
	memset(f, 0x3f, sizeof f);
	for(int len = 1; len <= n; ++len)
	{
		for(int l = 1; l + len - 1 <= n; ++l)
		{
			int r = l + len - 1;
			if(len == 1) f[l][r] = 0;
			else 
			{
				for(int k = l; k < r; ++k) f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);
			}
		}
	}
	
	cout << f[1][n] << endl;
	
	return 0;
}

二、环形石子合并

标签:DP、区间DP、环形区间DP

思路:对于环形区间问题其实就是在此基础上再加一条完全相等的区间,然后做长度为 n n n 的区间合并,最后枚举每个区间找最值即可。原因是环形的最后肯定会有一个缺口,这个缺口意味着两个相邻的点永远不会挨着合并,然后我们就枚举所有这样的缺口,最终展开的结果就是有 n n n 种链, n n n 种石子合并问题。只要记住区间 D P DP DP 的环形问题都是这样解决的就行了。
在这里插入图片描述

题目描述:

将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。

规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。

请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:

选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。选择一种合并石子的方案,使得做 n−1 次合并得分总和最小。

输入格式
第一行包含整数 n,表示共有 n 堆石子。

第二行包含 n 个整数,分别表示每堆石子的数量。

输出格式
输出共两行:

第一行为合并得分总和最小值,

第二行为合并得分总和最大值。

数据范围
1≤n≤200
输入样例:
4
4 5 9 4
输出样例:
43
54

示例代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y second

const int N = 410, M = N, INF = 0x3f3f3f3f;

int n, m;
int w[N], s[N], f[N][N], g[N][N];

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> w[i], w[i+n] = w[i];
	for(int i = 1; i <= n * 2; ++i) s[i] += s[i-1] + w[i];
	
	memset(f, 0x3f, sizeof f);
	memset(g, -0x3f, sizeof g);
	for(int len = 1; len <= n; ++len)
	{
		for(int l = 1; l + len - 1 <= n * 2; ++l)
		{
			int r = l + len - 1;
			if(len == 1) f[l][r] = g[l][r] = 0;
			else 
			{
			    for(int k = l; k < r; ++k) 
    			{
    				f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);
    				g[l][r] = max(g[l][r], g[l][k] + g[k+1][r] + s[r] - s[l-1]);
    			}
			}
		}
	}
	
	int minv = INF, maxv = -INF;
	for(int i = 1; i <= n; ++i)
	{
	    minv = min(minv, f[i][i+n-1]);
	    maxv = max(maxv, g[i][i+n-1]);
	}
	
	cout << minv << endl << maxv << endl;
	
	return 0;
}

三、能量项链

标签:DP、区间DP、破环成链

思路:思路其实还是上一题的思路,在后面再开一串相同的链就行了,不一样的是该题一个石子的参数有两个,意味着我们合并的时候是三个三个的合并,并且最终的答案是 f [ 1 ] [ n + 1 ] f[1][n+1] f[1][n+1] ,也是要包括自己的,因为由于题目给出的性质肯定最后是如下图的一种方式:
在这里插入图片描述在这里插入图片描述
所以最终的答案是包括自己的。再总结一下区间 D P DP DP 的思路,先把所有的状态置为非法,然后从 1 ∼ n 1\sim n 1n 枚举每一个区间,在此基础上将一些合法的区间初始化,比如这道题中区间长度小于 3 3 3 的值都为 0 0 0 ,然后就进行拆分取最值即可。

题目描述:

在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链,在项链上有 N 颗能量珠。

能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。

并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。

因为只有这样,通过吸盘(吸盘是 Mars 人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被
吸盘吸收的能量。

如果前一颗能量珠的头标记为 m,尾标记为 r,后一颗能量珠的头标记为 r,尾标记为 n,则聚合后释放的能量为 m×r×n
(Mars 单位),
新产生的珠子的头标记为 m,尾标记为 n。

需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。

显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设 N=4,4 颗珠子的头标记与尾标记依次为 (2,3)(3,5)(5,10)(10,2)。

我们用记号 ⊕ 表示两颗珠子的聚合操作,(j⊕k) 表示第 j,k 两颗珠子聚合后所释放的能量。则

第 4、1 两颗珠子聚合后释放的能量为:(4⊕1)=10×2×3=60。

这一串项链可以得到最优值的一个聚合顺序所释放的总能量为 ((4⊕1)⊕2)⊕3)=10×2×3+10×3×5+10×5×10=710。

输入格式
输入的第一行是一个正整数 N,表示项链上珠子的个数。

第二行是 N 个用空格隔开的正整数,所有的数均不超过 1000,第 i 个数为第 i 颗珠子的头标记,当 i<N 时,第 i 颗珠子的尾标记
应该等于第 i+1 颗珠子的头标记,第 N 颗珠子的尾标记应该等于第 1 颗珠子的头标记。

至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出格式
输出只有一行,是一个正整数 E,为一个最优聚合顺序所释放的总能量。

数据范围
4≤N≤100,1≤E≤2.1×109
输入样例:
4
2 3 5 10
输出样例:
710

示例代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y second

const int N = 210, M = N, INF = 0x3f3f3f3f;

int n, m;
int w[N], f[N][N];

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> w[i], w[i+n] = w[i];
	
	memset(f, -0x3f, sizeof f);
	for(int len = 1; len <= n + 1; ++len)
	{
		for(int l = 1; l + len - 1 <= n * 2; ++l)
		{
			int r = l + len - 1;
			if(len < 3) f[l][r] = 0; 
			else
			{
			    for(int k = l + 1; k < r; ++k)
    			{
    				f[l][r] = max(f[l][r], f[l][k] + f[k][r] + w[l] * w[k] * w[r]);	
    			}
			}
		}
	}
	
	int res = 0;
	for(int i = 1; i <= n; ++i)
	{
		res = max(res, f[i][i+n]);
	}
	
	cout << res << endl;
	
	return 0;
}

四、加分二叉树

标签:DP、区间DP

思路:首先需要构造一个中序遍历的二叉树,也就意味着如果根结点确定为 k k k 的话,那么它的左子树编号就为 1 ∼ k − 1 1\sim k-1 1k1 ,右子树的编号为 k + 1 ∼ n k+1\sim n k+1n ,那么也就意味着这道题是一道区间 D P DP DP 的问题,我们需要枚举每一个区间,然后对每一个区间枚举它的根结点,然后求出这个区间的最大值。这里注意的是叶子结点就是本身的值,然后空树的加分为 1 1 1 这意味着是在算根结点的加分值,而不是它本身的值,这是两个值需要区分,然后在其中对于空树特判一下即可。对于前序遍历我们可以记录下最优解的方案,定义数组 g [ l ] [ r g[l][r g[l][r 代表区间 [ l , r ] [l,r] [l,r] 的根结点,然后去递归这个过程,先输出根结点然后输出左子树的根结点,再输出右子树的根结点即可。然后区间 D P DP DP 整体的思路再说一遍,加深印象,先是将所有的状态赋为非法值,枚举区间长度,然后枚举左端点,并且右端点不能超过整个区间的长度,对于一些初始化值根据区间长度将其初始化,然后枚举区间划分的 k k k ,根据题目要求进行状态计算求最值。

题目描述:

设一个 n 个节点的二叉树 tree 的中序遍历为(1,2,3,…,n),其中数字 1,2,3,…,n 为节点编号。

每个节点都有一个分数(均为正整数),记第 i 个节点的分数为 di,tree 及它的每个子树都有一个加分,任一棵子树 subtree
(也包含 tree 本身)的加分计算方法如下:     

subtree的左子树的加分 × subtree的右子树的加分 + subtree的根的分数 

若某个子树为空,规定其加分为 1。

叶子的加分就是叶节点本身的分数,不考虑它的空子树。

试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树 tree。

要求输出: 

(1)tree的最高加分 

(2)tree的前序遍历

输入格式
第 1 行:一个整数 n,为节点个数。 

第 2 行:n 个用空格隔开的整数,为每个节点的分数(0<分数<100)。

输出格式
第 1 行:一个整数,为最高加分(结果不会超过int范围)。     

第 2 行:n 个用空格隔开的整数,为该树的前序遍历。如果存在多种方案,则输出字典序最小的方案。

数据范围
n<30
输入样例:
5
5 7 1 2 10
输出样例:
145
3 1 2 4 5

示例代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y second

const int N = 35, M = N, INF = 0x3f3f3f3f;

int n, m;
int w[N];
int f[N][N], g[N][N];

void dfs(int l, int r)
{
	if(l > r) return;
	int k = g[l][r];
	cout << k << " ";
	dfs(l,k-1), dfs(k+1,r);
}

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> w[i];
	
	memset(f, -0x3f, sizeof f);
	for(int len = 1; len <= n; ++len)
	{
		for(int l = 1; l + len - 1 <= n; ++l)
		{
			int r = l + len - 1;
			if(len == 1) f[l][r] = w[l], g[l][r] = l;
			else
			{
				for(int k = l; k <= r; ++k)
				{
					int left = k == l ? 1 : f[l][k-1];
					int right = k == r ? 1 : f[k+1][r];
					int score = left * right + w[k];
					if(score > f[l][r])
					{
						f[l][r] = score;
						g[l][r] = k;
					}
				}
			}
		}
	}
	
	cout << f[1][n] << endl;
	dfs(1,n);
	
	return 0;
}

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

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

相关文章

PLC工程师按这个等级划分是否靠谱?

在工业自动化领域&#xff0c;PLC工程师扮演着至关重要的角色&#xff0c;他们负责构建、维护自动化系统&#xff0c;推动工业4.0进程的发展。成为一名优秀的PLC工程师需要经历不同境界的发展阶段&#xff0c;每个阶段都对应着不同的技能要求和责任。以下是PLC工程师的六种级别…

必应bing国内推广开户,全方位必应广告开户流程介绍!

在所有获客渠道中&#xff0c;搜索引擎广告成为企业扩大品牌影响力、精准触达目标客户的关键途径之一。作为全球领先的搜索引擎之一&#xff0c;必应&#xff08;Bing&#xff09;拥有庞大的用户群体和独特的市场优势&#xff0c;是企业不可忽视的营销阵地。云衔科技&#xff0…

声音转文本(免费工具)

声音转文本&#xff1a;解锁语音技术的无限可能 在当今这个数字化时代&#xff0c;信息的传递方式正以前所未有的速度进化。从手动输入到触控操作&#xff0c;再到如今的语音交互&#xff0c;技术的发展让沟通变得更加自然与高效。声音转文本&#xff08;Speech-to-Text, STT&…

微服务:利用RestTemplate实现远程调用

打算系统学习一下微服务知识&#xff0c;从今天开始记录。 远程调用 调用order接口&#xff0c;查询。 由于实现还未封装用户信息&#xff0c;所以为null。 下面我们来使用远程调用用户服务的接口&#xff0c;然后封装一下用户信息返回即可。 流程图 配置类中注入RestTe…

SAP销售手工发票录入

销售手工发票录入用于处理未启用 SD 模块标准处理流程的零星销售业务。 科目设置 收入类科目&#xff1a;设置税务类型&#xff0c;允许含税/不含税过账应收账款: 留空。其他应收款的设置类似 编辑选项设置 在中国&#xff0c;编辑选项一般设置为基于总额计税。使用事务码 FB…

Jenkins 构建 Web 项目:项目和服务器在一起的情况

构建的命令 node -v pnpm -v pnpm install pnpm build # 将dist打包成dist.zip zip -r dist.zip dist mv dist.zip /www/wwwroot/video.xxx.com/dist.zip cd /www/wwwroot/video.xxx.com # 解压并覆盖之前的文件 unzip -o dist.zip

期货学习笔记-横盘行情学习1

横盘行情的特征及分类 横盘行情的概念 横盘行情时中继形态的一种&#xff0c;一般常出现在大涨或大跌之后出现横盘行情是对当前趋势行情的修正&#xff0c;是对市场零散筹码的清理&#xff0c;是为了集中筹码更便于后期行情的展开 横盘行情的特征 1.水平运动&#xff1a;该…

1-4月我国5G用户、流量占比均过半,呈现平稳增长态势!

1-4月份&#xff0c;通信行业整体运行平稳。电信业务量收平稳增长&#xff1b;5G、千兆光网等新型基础设施建设持续推进&#xff0c;网络连接用户规模不断扩大&#xff0c;移动互联网接入流量较快增长。 一、总体运行情况 电信业务收入稳步增长&#xff0c;电信业务总量增速保持…

OpenAI宫斗剧番外篇: “Ilya与Altman联手对抗微软大帝,扫除黑恶势力”,“余华”和“莫言”犀利点评

事情是这样的。 小编我是一个重度的智谱清言用户&#xff0c;最近智谱清言悄悄上线了一个“划词引用”功能后&#xff0c;我仿佛打开了新世界的大门。我甚至用这个小功能&#xff0c;玩出来了即将为你上映的《OpenAI宫斗剧番外篇》。 3.5研究测试&#xff1a;hujiaoai.cn 4研…

别说废话!说话说到点上,项目高效沟通的底层逻辑揭秘

假设你下周要在领导和同事面前汇报项目进度&#xff0c;你会怎么做&#xff1f;很多人可能会去网上搜一个项目介绍模板&#xff0c;然后按照模板来填充内容。最后&#xff0c;汇报幻灯片做了 80 页&#xff0c;自己觉得非常充实&#xff0c;但是却被领导痛批了一顿。 这样的境…

番外篇 | YOLOv8改进之引入YOLOv9的RepNCSPELAN4模块 | 替换YOLOv8的C2f

前言:Hello大家好,我是小哥谈。YOLOv9,作为YOLO(You Only Look Once)系列的最新成员,代表着实时物体检测技术的又一重要里程碑。自YOLO系列算法诞生以来,它就以其出色的性能和简洁的设计思想赢得了广泛的关注和认可。从最初的YOLOv1到如今的YOLOv9,这个系列不断地进行技…

C++初阶学习第十弹——探索STL奥秘(五)——深入讲解vector的迭代器失效问题

vector&#xff08;上&#xff09;&#xff1a;C初阶学习第八弹——探索STL奥秘&#xff08;三&#xff09;——深入刨析vector的使用-CSDN博客 vector&#xff08;中&#xff09;&#xff1a;C初阶学习第九弹——探索STL奥秘&#xff08;四&#xff09;——vector的深层挖掘和…

二十五、openlayers官网示例CustomOverviewMap解析——实现鹰眼地图、预览窗口、小窗窗口地图、旋转控件

官网demo地址&#xff1a; Custom Overview Map 这个示例展示了如何在地图上增加一个小窗窗口的地图并跟随着地图的旋转而旋转视角。 首先加载了一个地图。其中 DragRotateAndZoom是一个交互事件&#xff0c;它可以实现按住shift键鼠标拖拽旋转地图。 const map new Map({int…

LSTM实例解析

大家好&#xff0c;这里是七七&#xff0c;今天带给大家的实例解析。以前也用过几次LSTM模型&#xff0c;但由于原理不是很清楚&#xff0c;因此不能清晰地表达出来&#xff0c;这次用LSTM的时候&#xff0c;去自习研究了原理以及代码&#xff0c;来分享给大家此次经历。 一、简…

《Python编程从入门到实践》day37

# 昨日知识点回顾 制定规范、创建虚拟环境并激活&#xff0c;正在虚拟环境创建项目、数据库和应用程序 # 今日知识点学习 18.2.4 定义模型Entry # models.py from django.db import models# Create your models here. class Topic(models.Model):"""用户学习的…

Vitis HLS 学习笔记--控制驱动TLP - Dataflow视图

目录 1. 简介 2. 功能特性 2.1 Dataflow Viewer 的功能 2.2 Dataflow 和 Pipeline 的区别 3. 具体演示 4. 总结 1. 简介 Dataflow视图&#xff0c;即数据流查看器。 DATAFLOW优化属于一种动态优化过程&#xff0c;其完整性依赖于与RTL协同仿真的完成。因此&#xff0c;…

微软开发者大会,Copilot Agents发布,掀起新一轮生产力革命!

把AI融入生产力工具的未来会是什么样&#xff1f;微软今天给出了蓝图。 今天凌晨&#xff0c;微软召开了Microsoft Build 2024 开发者大会&#xff0c;同前两天的Google I/O开发者大会一样&#xff0c;本次大会的核心词还是“AI”&#xff0c;其中最主要的内容是最新的Copilot…

如何提交网站到谷歌网站收录?

其实就那么几个步骤&#xff0c;要做谷歌那肯定是需要一个谷歌账号的&#xff0c;然后找到Google Search Console这个谷歌的官方平台&#xff0c;这是最权威的可以统计来自谷歌流量的平台了&#xff0c;毕竟是谷歌自家的&#xff0c;肯定也不可能作假&#xff0c;然后就是跟着平…

Kubernetes——Pod详解

目录 一、Pod基础概念 1.概念 2.使用方式 3.Pause容器 3.1网络 3.2存储 4.Pod容器分类 4.1自主式Pod 4.2控制器管理的Pod 二、Pod的分类 1.基础容器&#xff08;infrastructure container&#xff09; 2.初始化容器&#xff08;initcontainers&#xff09; 2.1Ini…

如何使用Docker快速运行Firefox并实现远程访问本地火狐浏览器

文章目录 1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox Firefox是一款免费开源的网页浏览器&#xff0c;由Mozilla基金会开发和维护。它是第一个成功挑战微软Internet Explorer浏…