【动态规划】【数学】1388. 3n 块披萨

news2025/2/3 14:00:58

作者推荐

【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数

本文涉及知识点

动态规划汇总

LeetCode1388 3n 块披萨

给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨:
你挑选 任意 一块披萨。
Alice 将会挑选你所选择的披萨逆时针方向的下一块披萨。
Bob 将会挑选你所选择的披萨顺时针方向的下一块披萨。
重复上述过程直到没有披萨剩下。
每一块披萨的大小按顺时针方向由循环数组 slices 表示。
请你返回你可以获得的披萨大小总和的最大值。
示例 1:
输入:slices = [1,2,3,4,5,6]
输出:10
解释:选择大小为 4 的披萨,Alice 和 Bob 分别挑选大小为 3 和 5 的披萨。然后你选择大小为 6 的披萨,Alice 和 Bob 分别挑选大小为 2 和 1 的披萨。你获得的披萨总大小为 4 + 6 = 10 。
示例 2:
输入:slices = [8,9,8,6,1,1]
输出:16
解释:两轮都选大小为 8 的披萨。如果你选择大小为 9 的披萨,你的朋友们就会选择大小为 8 的披萨,这种情况下你的总和不是最大的。
提示:
1 <= slices.length <= 500
slices.length % 3 == 0
1 <= slices[i] <= 1000

动态规划

原理

题目等效于以下描述:
从[0,3n)中选择n个不相邻的数据,注意:0和3n-1是相邻。
题目一定符合描述: 因为相邻的数被Alice Bob 取走了。
描述一定符合题意,证明如下:
a,n=1,只有一个数必定不相邻。
b,n >1 。必定有两个选取的数之间有两个或以上的数。反证法:如果任何两个选取的数之间都只有一个数,那数的总数量是2n,和3n矛盾。对勾表示选取,X表示没选取。 ⋯ X ✓ X ‾ X ✓ X ⋯ \cdots \underline{ X \checkmark X} X \checkmark X \cdots XXXX
我们将下划线部分删除,变成 ⋯ X ✓ X ⋯ \cdots X \checkmark X \cdots XX 仍然符合描述,但n减少了1。不断迭代n,当n为1时,证明成立。

动态规划的状态表示

pre[b1][b2][k] 表示[0,i)中选取了k个数的最大值,b1是否选择了i-1,b2是否选择了0。
dp类似,表示[0,i+1)的情况。

动态规划的转移方程

当前数 没选择。
b1 变成0。其它不变。
下面分析选取的情况:
b11=true b21=b2 k1=k+1
k的取值范围:[0,n-1)
dp[b11][b21][k1] = max( ⋯ \cdots ,pre[b1][b2][k]+arr[i])
如果b1等于true,忽略。如果i为3n-1,且b2,忽略。

动态规划的初始值

pre[1][1][1] = arr[0]
pre[0][0][0] = 0
其它 -1e6表示非法状态

动态规划的填表顺序

i从1到3n-1

动态规划的返回值

max(dp[0][0].back() + dp[0][1].back(),dp[1][0].back()+dp[1][1].back())

代码

核心代码

class Solution {
public:
	int maxSizeSlices(vector<int>& slices) {
		const int n3 = slices.size();
		const int n = n3 / 3;
		vector<vector<vector<int>>> pre(2, vector<vector<int>>(2, vector<int>(n + 1, m_iNotMay)));
		pre[1][1][1] = slices[0];
		pre[0][0][0] = 0;
		for (int i = 1; i < n3; i++)
		{
			vector<vector<vector<int>>> dp(2, vector<vector<int>>(2, vector<int>(n + 1, m_iNotMay)));
			//不选择slices[i]
			for (int i2 = 0; i2 < 2; i2++)
			{
				for (int i3 = 0; i3 <= n; i3++)
				{
					dp[0][i2][i3] = max(pre[0][i2][i3], pre[1][i2][i3]);
				}
			}
			//选择
			{
				for (int i3 = 0; i3 < n; i3++)
				{
					dp[1][0][i3+1] = max(dp[1][0][i3+1], pre[0][0][i3] + slices[i]);
				}
			}
			if (n3 - 1 != i)
			{
				for (int i3 = 0; i3 < n; i3++)
				{
					dp[1][1][i3+1] = max(dp[1][1][i3+1], pre[0][1][i3] + slices[i]);
				}
			}
			pre.swap(dp);
		}
		vector<int> vMax = { pre[0][0].back(), pre[0][1].back(),pre[1][0].back(),pre[1][1].back() };
		return *std::max_element(vMax.begin(), vMax.end());
	}
	const int m_iNotMay = -1000'000;
};

测试用例

int main()
{	
	vector<int> slices;
	int d;
	{
		Solution sln;
		slices = { 1, 2, 3, 4, 5, 6 };
		auto res = sln.maxSizeSlices(slices);
		Assert(10, res);
	}
	{
		Solution sln;
		slices = { 8,9,8,6,1,1 };
		auto res = sln.maxSizeSlices(slices);
		Assert(16, res);
	}
	{
		Solution sln;
		slices = { 9,5,1,7,8,4,4,5,5,8,7,7 };
		auto res = sln.maxSizeSlices(slices);
		Assert(30, res);
	}
	{
		Solution sln;
		slices = { 10,9,1,10,8,5,10,2,2 };
		auto res = sln.maxSizeSlices(slices);
		Assert(30, res);
	}
	{
		Solution sln;
		slices = { 4,1,2,5,8,3,1,9,7 };
		auto res = sln.maxSizeSlices(slices);
		Assert(21, res);
	}
}

优化

关于0和3n-1不能同时选择的解决方法:
情况一:选择了0,没有选择3n-1。
情况二:选择了3n-1,没有选择0。
情况三:两者都没选择。

只处理slices的前3n-1个元素,可以枚举所有的情况一和情况三。
值处理slices的后3n-1个元素,可以枚举所有的情况一和情况三。

class Solution {
public:
	int maxSizeSlices(vector<int>& slices) {
		const int n3 = slices.size();
		const int n = n3 / 3;
		return max(Do(slices.data(),n3-1,n), Do(slices.data()+1, n3 - 1, n));
	}
	int Do(int* slices, int len, int n)
	{
		vector<vector<int>> pre(2, vector<int>(n + 1, m_iNotMay));
		pre[0][0] = 0;
		pre[1][1] = slices[0];
		for (int i = 1; i < len; i++)
		{
			vector<vector<int>> dp(2, vector<int>(n + 1, m_iNotMay));			
			for (int i2 = 0; i2 <= n; i2++)
			{//不选择
				dp[0][i2] = max(pre[0][i2], pre[1][i2]);
			}
			for (int i2 = 0; i2 < n; i2++)
			{
				dp[1][i2+1] = max(pre[1][i2+1], pre[0][i2]+slices[i]);
			}
			pre.swap(dp);
		}
		return max(pre[0].back(), pre[1].back());
	}
	const int m_iNotMay = -1000'000;
};

2023年2月版

class Solution {
public:
int maxSizeSlices(vector& slices) {
m_c = slices.size();
vector<vector> dp(m_c/3+1,vector(m_c));
{
for (int i = 0; i < m_c; i++)
{
dp[1][i] = slices[GetIndex(i + 1)];
}
}
for (int len = 6; len <= m_c; len += 3)
{
for (int iPos = 0; iPos < m_c; iPos++)
{
int iMaxValue = 0;
//可以拆分2个
for (int j = 3; j < len; j += 3)
{
int iVaue = dp[j/3][iPos] + dp[(len-j) / 3][GetIndex( iPos+j)];
iMaxValue = max(iMaxValue, iVaue);
}
//消除两端元素和中间元素
for (int j = 1; j < len; j+=3 )
{
int iVaue = slices[GetIndex(iPos + j)] + dp[(j - 1) / 3][GetIndex(iPos + 1)];
const int iRightLen = (len - j -2 ) / 3;
if ( iRightLen > 0 )
{
iVaue += dp[iRightLen][GetIndex(iPos + j + 1)];
}
iMaxValue = max(iMaxValue, iVaue);
}
dp[len / 3][iPos] = iMaxValue;
}
}
auto& pre = dp[m_c / 3];
return *std::max_element(pre.begin(), pre.end());
}
int GetIndex(int index)
{
return (index + m_c)%m_c;
}
int m_c;
};

2023年8月版

class Solution {
public:
int maxSizeSlices(vector& slices) {
needSel = slices.size() / 3;
vector<vector<vector>> pre(2, vector<vector>(2, vector(needSel+1, -1000 * 1000)));
pre[0][0][0] = 0; //pre[i][j][k] i是否选择第0个元素,j前一个元素是否被选择,已经选择了多少个
for (int i = 0; i < slices.size(); i++)
{
vector<vector<vector>> dp(2, vector<vector>(2, vector(needSel + 1, -1000 * 1000)));
for (auto sel0 = 0; sel0 < 2; sel0++)
{
for (auto selPre = 0; selPre < 2; selPre++)
{
for (int hasSel = 0; hasSel <= needSel; hasSel++)
{
//不选择
dp[sel0][0][hasSel] = max(dp[sel0][0][hasSel],pre[sel0][selPre][hasSel]);
//选择
bool bCanSel = (hasSel < needSel) && (!selPre);
if (sel0 && (i + 1 == slices.size()))
{
bCanSel = false;
}
if (bCanSel)
{
bool sel0cur = sel0 || (0 == i);
dp[sel0cur][1][hasSel+1] = max(dp[sel0cur][1][hasSel + 1], pre[sel0][selPre][hasSel] + slices[i]);
}
}
}
}
pre.swap(dp);
}
int iMax = 0;
for (auto sel0 = 0; sel0 < 2; sel0++)
{
for (auto selPre = 0; selPre < 2; selPre++)
{
iMax = max(iMax, pre[sel0][selPre].back());
}
}
return iMax;
}
int needSel;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

腾讯mini项目总结-指标监控服务重构

项目概述 本项目的背景是&#xff0c;当前企业内部使用的指标监控服务的方案的成本很高&#xff0c;无法符合用户的需求&#xff0c;于是需要调研并对比测试市面上比较热门的几款开源的监控方案&#xff08;选择了通用的OpenTelemetry协议&#xff1a;Signoz&#xff0c;otel-…

基于SpringBoot的社区报修维修管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 一、项目简介 21世纪的今天&#xff0…

QT使用QFileSystemModel实现的文件资源管理器(开源)

文章目录 效果图现实的功能总体框架功能介绍视图双击进入处理复制与剪切粘贴重命名&#xff0c;新建显示文件详细信息文件路径导航栏 总结 效果图 现实的功能 支持文件/文件夹复制&#xff0c;粘贴&#xff0c;剪切&#xff0c;删除&#xff0c;重命名的基本操作支持打开图片&…

zookeeper搭建(单机模式和集群模式)

目录 单机模式&#xff1a; 集群搭建&#xff1a; 单机模式&#xff1a; 1.新建data和logs目录(data目录用来存放数据库快照&#xff0c;logs目录用来存放日志文件) [rootmaster dev]# mkdir -p /home/apps/zookeeper/data [rootmaster dev]# mkdir -p /home/apps/zookeeper/…

静态代理IP是如何助力跨境电商运营的?

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

ROS1入门之节点与指令

文章目录 前言一、RO1的安装与测试1.ROS1安装2.ROS1测试 二、ROS1创建节点1.创建工作空间2.创建功能包3.创建节点4.配置CMakeLists5.编译运行节点&#x1f349;编译节点&#x1f353;source环境&#x1f34e;运行节点 三、ROS1常用指令1.rosnode✨rosnode list&#x1f38a;ros…

C++进阶--多态

概念 多态是面向对象编程中的一个重要概念&#xff0c;它允许不同类型的对象对同一个消息做出不同的响应。具体的来说&#xff0c;当相同的消息传递给不同的对象时&#xff0c;这些对象能够以不同的方式进行处理&#xff0c;从而产生不同的行为。 对于多态的实现&#xff0c;…

FLASH存放uboot及VxWorks并引导自启动

本文使用飞腾E2000Q miniITX开发板,验证在E2000启动用的qspi flash中同时写入uboot固件和vxWorks镜像,并测试开机自动引导启动。 一、环境准备: 1.1 硬件环境: 1.E2000Q miniITX行业开发板一块 2.U盘一个 3.TTL调试串口线一条 1.2 软件环境: 1.做好的vxWorks.bin(公…

2024美赛数学建模A题思路源码——七鳃鳗性别比例和生态系统关系

赛题目的:分析一个物种根据资源可用性改变其性别比例的能力的利弊。开发一个模型,分析对生态系统中由此产生的相互作用。 问题一.七鳃鳗性别比例对生态系统的影响 问题分析 建立一个简化版的模型,来探讨以下问题: 1.我们假设七鳃鳗种群的增长遵循Logistic生长模型,其中食…

Linux网络编程 基础

OSI七层模型 物理层&#xff1a;主要定义物理设备标准&#xff0c;如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流&#xff08;就是由1、0转化为电流强弱来进行传输&#xff0c;到达目的地后再转化为1、0&#xff0c;也就是我们常说的…

《HTML 简易速速上手小册》第9章:HTML5 新特性(2024 最新版)

文章目录 9.1 HTML5 新增标签和属性9.1.1 基础知识9.1.2 案例 1&#xff1a;创建一个结构化的博客页面9.1.3 案例 2&#xff1a;使用新的表单元素创建事件注册表单9.1.4 案例 3&#xff1a;创建一个具有高级搜索功能的搜索表单 9.2 HTML5 表单增强9.2.1 基础知识9.2.2 案例 1&a…

海洋鱼类检测7种YOLOV8NANO

【免费】海洋鱼类检测&#xff0c;7种类型&#xff0c;YOLOV8训练&#xff0c;转换成ONNX&#xff0c;OPENCV调用资源-CSDN文库 采用YOLOV8NANO训练模型&#xff0c;得到PT模型&#xff0c;然后转换成ONNX&#xff0c;供OPENCV的DNN调用&#xff0c;摆脱PYTORCH依赖&#xff0c…

中小学电子编程内部集中培训第五课

超声波 小车例程 测试距离 此程序把超声波测量的距离通过串口打印出来&#xff0c;程序中会用到控制模块中的 初始化&#xff0c;串口模块中的比特率设置、Serial 打印和 Serial 打印自动换行&#xff0c;云开智 能中的超声波测距模块&#xff0c;完成后如图 19-1&#xff1a;…

RK3588开发板Ubuntu与开发板使用U盘互传

1 将 U 盘(U 盘的格式必须为 FAT32 格式&#xff0c;大小在 32G 以下)插到开发板的 usb 接口&#xff0c;串口打印信息如下所示&#xff0c;U 盘的设备节点是/dev/sdb4。U 盘的设备节点不是固定的&#xff0c;根据实际情况来查看设备节点。 2 输入以下命令挂载 U 盘&#xff0c…

ssl数字证书是什么

SSL证书是一种数字证书&#xff0c;用于在网络传输中提供加密和身份验证功能&#xff0c;从而保护数据的安全性和完整性。正规的SSL证书大多是由由权威的证书颁发机构&#xff08;CA&#xff09;颁发的&#xff0c;例如Certum、Digicert、Sectigo等&#xff0c;它们颁发的SSL数…

Qt多线程与SocketTCP的简单实现

1.相关说明 多线程实现Qt的socket编程实现客户端发送文件&#xff0c;服务端接收文件&#xff0c;并且在客户端设置了心跳&#xff0c;用于监控服务端是否存活。因为Qt中socket套接字发送数据&#xff0c;会先把数据发送至缓冲区中&#xff0c;在发送数据过程中&#xff0c;soc…

基于Transformer结构的扩散模型综述

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

【Qt基本功修炼】Qt线程的两种运行模式

1. 前言 QThread是Qt中的线程类&#xff0c;用于实现多线程运行。 QThread有两种工作模式&#xff0c;即 消息循环模式无消息循环模式 两种模式分别适用于不同的场景。下面我们将从多个方面&#xff0c;讲解QThread两种工作模式的区别。 2. 消息循环模式 2.1 实现原理 Q…

Tomcat 部署项目时 war 和 war exploded区别

在 Tomcat 调试部署的时候&#xff0c;我们通常会看到有下面 2 个选项。 是选择war还是war exploded 这里首先看一下他们两个的区别&#xff1a; war 模式&#xff1a;将WEB工程以包的形式上传到服务器 &#xff1b;war exploded 模式&#xff1a;将WEB工程以当前文件夹的位置…

《Pandas 简易速速上手小册》第5章:Pandas 数据合并与重塑(2024 最新版)

文章目录 5.1 数据合并&#xff1a;Concatenate 和 Merge5.1.1 基础知识5.1.2 重点案例&#xff1a;客户订单数据合并5.1.3 拓展案例一&#xff1a;产品目录和销售数据合并5.1.4 拓展案例二&#xff1a;员工信息和部门数据合并 5.2 数据透视和重塑5.2.1 基础知识5.2.2 重点案例…