【动态规划】【前缀和】【推荐】2463. 最小移动总距离

news2024/11/19 7:36:21

作者推荐

【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子

本文涉及知识点

动态规划汇总
C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

2463. 最小移动总距离

X 轴上有一些机器人和工厂。给你一个整数数组 robot ,其中 robot[i] 是第 i 个机器人的位置。再给你一个二维整数数组 factory ,其中 factory[j] = [positionj, limitj] ,表示第 j 个工厂的位置在 positionj ,且第 j 个工厂最多可以修理 limitj 个机器人。
每个机器人所在的位置 互不相同 。每个工厂所在的位置也 互不相同 。注意一个机器人可能一开始跟一个工厂在 相同的位置 。
所有机器人一开始都是坏的,他们会沿着设定的方向一直移动。设定的方向要么是 X 轴的正方向,要么是 X 轴的负方向。当一个机器人经过一个没达到上限的工厂时,这个工厂会维修这个机器人,且机器人停止移动。
任何时刻,你都可以设置 部分 机器人的移动方向。你的目标是最小化所有机器人总的移动距离。
请你返回所有机器人移动的最小总距离。测试数据保证所有机器人都可以被维修。
注意:
所有机器人移动速度相同。
如果两个机器人移动方向相同,它们永远不会碰撞。
如果两个机器人迎面相遇,它们也不会碰撞,它们彼此之间会擦肩而过。
如果一个机器人经过了一个已经达到上限的工厂,机器人会当作工厂不存在,继续移动。
机器人从位置 x 到位置 y 的移动距离为 |y - x| 。
示例 1:
输入:robot = [0,4,6], factory = [[2,2],[6,2]]
输出:4
解释:如上图所示:

  • 第一个机器人从位置 0 沿着正方向移动,在第一个工厂处维修。
  • 第二个机器人从位置 4 沿着负方向移动,在第一个工厂处维修。
  • 第三个机器人在位置 6 被第二个工厂维修,它不需要移动。
    第一个工厂的维修上限是 2 ,它维修了 2 个机器人。
    第二个工厂的维修上限是 2 ,它维修了 1 个机器人。
    总移动距离是 |2 - 0| + |2 - 4| + |6 - 6| = 4 。没有办法得到比 4 更少的总移动距离。
    示例 2:
    输入:robot = [1,-1], factory = [[-2,1],[2,1]]
    输出:2
    解释:如上图所示:
  • 第一个机器人从位置 1 沿着正方向移动,在第二个工厂处维修。
  • 第二个机器人在位置 -1 沿着负方向移动,在第一个工厂处维修。
    第一个工厂的维修上限是 1 ,它维修了 1 个机器人。
    第二个工厂的维修上限是 1 ,它维修了 1 个机器人。
    总移动距离是 |2 - 1| + |(-2) - (-1)| = 2 。没有办法得到比 2 更少的总移动距离。
    提示:
    1 <= robot.length, factory.length <= 100
    factory[j].length == 2
    -109 <= robot[i], positionj <= 109
    0 <= limitj <= robot.length
    测试数据保证所有机器人都可以被维修。

动态规划

原理

性质一:r1和r2是两个机器人位置,且r1 < r2。令f1和r2是两个工厂位置,且f1 < f2。 选择一:f1修r1,f2修r2。选择二:f1修r2,f2修f1。方式一不劣于方式二
下面分情况证明:
一,r2 <= f1。两个机器人都在左边,两种选择结果一样。可以这样理解,两个机器人都进f1,然后其中一个去f2。
二,r1 >= f2。两个机器人都在右边。两种选择结果一样。可以这样理解:两个机器人都近f2,然后其中一个去f1。
三,f1 < r1 < r2 < f2。绿线是选择一,红线是选择二。在这里插入图片描述
四,r1 < f1 f1 < r2 < f2 。
在这里插入图片描述
五,r1 < f1 r2 > f2。

在这里插入图片描述
六,f1<r1<f2 r2<r2。和情况四对称。

动态规划的状态表示

dp[i][j] 前i个工厂修理前j个机器人的最小移动距离。

动态规划的转移方程

最左边的i个工厂,修理了j个机器人,最后一个工厂修理了k个机器人。根据性质一,则这k个机器人一定是j个机器人中最右边的。
dp[i][j] = m i n k : 0 m i n ( l i m i t [ i ] , j ) \Large min_{k:0}^{min(limit[i],j)} mink:0min(limit[i],j) (pre[i-1][j-k])+移动k个机器人的总距离
左移的机器人和右移的机器人,分别利用前缀和计算总距离。先对机器人和工厂的位置排序,坐标小于等于工厂坐标机器人右移:
∑ 移动的机器人 ( 工厂到原点距离 − 机器人到原点的距离 ) → \sum _{移动的机器人} (工厂到原点距离-机器人到原点的距离) \rightarrow 移动的机器人(工厂到原点距离机器人到原点的距离) 工厂到原点的距离 ⋆ 移动的机器人数 − ∑ 移动的机器人 ( 机器人到原点的距离 ) 工厂到原点的距离\star 移动的机器人数 - \sum _{移动的机器人}(机器人到原点的距离) 工厂到原点的距离移动的机器人数移动的机器人(机器人到原点的距离)

动态规划的初始值

dp[0][0]=0 其它3e11

动态规划的填表顺序

从左到右计算后置状态。

返回值

dp.back().back()

注意
前缀和记录的是相对位置:坐标是负数也可以。

代码

核心代码

template<class ELE,class ELE2>
void MinSelf(ELE* seft, const ELE2& other)
{
	*seft = min(*seft,(ELE) other);
}

template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{
	*seft = max(*seft, other);
}

template<class T = long long >
class CPreSum
{
public:
	CPreSum(const vector<int>& nums)
	{
		m_data.push_back(0);
		for (int i = 0; i < nums.size(); i++)
		{
			m_data.push_back(m_data[i] + nums[i]);
		}
	}
	template<class _PR>
	CPreSum(int iSize, _PR pr)
	{
		m_data.push_back(0);
		for (int i = 0; i < iSize; i++)
		{
			m_data.push_back(m_data[i] + pr(i));
		}
	}
	T Sum(int left, int rightExclu)const
	{
		return m_data[rightExclu] - m_data[left];
	}
protected:
	vector<T> m_data;
};

class Solution {
public:
	long long minimumTotalDistance(vector<int>& robot, vector<vector<int>>& factory) {
		sort(robot.begin(), robot.end());
		sort(factory.begin(), factory.end(), [&factory](auto& v1,auto& v2) {return v1[0] <v2[0]; });
	
		int n1 = factory.size(), n2 = robot.size();
		vector<int> vLeftCount;
		for (int i = 0, j = 0; i < n1; i++)
		{
			while ((j < n2) && (robot[j] <= factory[i][0]))
			{
				j++;
			}
			vLeftCount.emplace_back(j);
		}
		CPreSum preSum(robot);
		vector<vector<long long>> dp(n1 + 1, vector<long long>(n2 + 1,3e11));
		dp[0][0] = 0;
		for (int i = 1; i <= n1; i++)
		{
			dp[i][0] = 0;
			for (int j = 1; j <= n2; j++)
			{
				for (int k = 0; k <= min(j, factory[i - 1][1]); k++)
				{
					const long long iLefttMove = min(k,max(0, j - vLeftCount[i - 1]));
					const long long llRightMove = k - iLefttMove;
					long long llMove = preSum.Sum(j - iLefttMove, j) - iLefttMove * factory[i - 1][0];//左移
					llMove += factory[i - 1][0] * llRightMove - preSum.Sum(j-k,j-k+llRightMove);
					MinSelf(&dp[i][j], dp[i - 1][j - k] + llMove);
				}
			}
		}
		return dp.back().back();
	}	
};

核心代码

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{	
	vector<int> robot;
	vector<vector<int>> factory;
	{
		Solution sln;
		robot = { 0,4,6 }, factory = { {2,2},{6,2} };
		auto res = sln.minimumTotalDistance(robot,factory);
		Assert(res,4LL);
	}

	{
		Solution sln;
		robot = { 1,-1 }, factory = { {-2,1},{2,1} };
		auto res = sln.minimumTotalDistance(robot, factory);
		Assert(res, 2LL);
	}


	{
		Solution sln;
		robot = { 0,4,6 }, factory = { {-2,2},{-6,2} };
		auto res = sln.minimumTotalDistance(robot, factory);
		Assert(res, 20LL);
	}
		
}

2023年2月

class Solution {
public:
long long minimumTotalDistance(vector& robot, vector<vector>& factory) {
m_c = robot.size();
std::sort(robot.begin(), robot.end());
std::sort(factory.begin(), factory.end(), [](const vector& v0, const vector& v1)
{
return v0[0] < v1[0];
});
vector vPre(m_c + 1, m_llNotMay);
vPre[0] = 0;
for (const auto& v : factory)
{
vector dp = vPre;
for (int i = 0; i < m_c; i++)
{
if (m_llNotMay == vPre[i])
{
continue;
}
long long llMove = 0;
for (int j = 1; j <= v[1]; j++)
{
if (i + j > m_c)
{
break;
}
llMove += abs(v[0] - robot[i + j - 1]);
dp[i + j] = min(dp[i + j], vPre[i] + llMove);
}
}
vPre.swap(dp);
}
return vPre[m_c];
}
int m_c;
const long long m_llNotMay = ((long long)INT_MAX) * 1000;
};

2023年8月

class Solution {
public:
long long minimumTotalDistance(vector& robot, vector<vector>& factory) {
m_c = robot.size();
std::sort(robot.begin(), robot.end());
std::sort(factory.begin(), factory.end(), [](const vector& v1, const vector& v2)
{return v1[0] < v2[0]; });
vector vPre(m_c + 1, m_llNotMay);//vPre[i] 当前工厂及更早工厂修理i个机器人的最小移动距离
vPre[0] = 0;
for (const auto& v : factory)
{
vector dp = vPre;//本工厂不修理机器人
for (int pre = 0; pre < m_c; pre++)
{
long long llMove = 0;
for (int iDo = 1; iDo <= v[1]; iDo++)
{
const int next = pre + iDo;
if (next > m_c)
{
break;
}
llMove += abs(robot[next-1] - v[0]);
dp[next] = min(dp[next], vPre[pre] + llMove);
}
}
vPre.swap(dp);
}
return vPre.back();
}
int m_c;
const long long m_llNotMay = 1e12;
};

2023年9月

class Solution {
public:
long long minimumTotalDistance(vector& robot, vector<vector>& factory) {
sort(robot.begin(), robot.end());
sort(factory.begin(), factory.end(), [](const vector& v1, const vector& v2)
{
return v1[0] < v2[0];
});
long long llMinPos = min(*robot.begin(),(*factory.begin())[0]);
vector vPreSumDis(1);
for (const auto& n : robot)
{
vPreSumDis.emplace_back(vPreSumDis.back() + n- llMinPos);
}
vector pre(1);//pre[i] 当前站点之前的站点修改i个机器人的最小成本
int iRight = 0;//当前工厂右边的第一个机器人
for (int i = 0; i < factory.size(); i++)
{
const int iFactoryPos = factory[i][0];
for (; (iRight < robot.size()) && (robot[iRight] <= iFactoryPos); iRight++);
const int iSize = min(robot.size(), pre.size()-1 + factory[i][1]);
vector dp(iSize+1,1e12);
for (int j = 0; j<pre.size(); j++)
{
for (int k = 0; (k <= factory[i][1])&&(j+k <= robot.size()); k++)
{//[j,iRight)个机器上右移[iRight,j+k)个机器人左右移
const long long llMove = MoveRight(j, min(j + k, iRight), iFactoryPos, llMinPos, vPreSumDis)+
MoveLeft(max(j,iRight),j+k, iFactoryPos, llMinPos, vPreSumDis);
dp[j + k] = min(dp[j + k], llMove+pre[j]);
}
}
pre.swap(dp);
}
return pre.back();
}
long long MoveRight(int left, int right,const int iFactoryPos,const long long llMinPos, const vector& vPreSumDis)
{
if (right <= left )
{
return 0;
}
return (long long)(right - left) * (iFactoryPos - llMinPos) - (vPreSumDis[right] - vPreSumDis[left]);
}
long long MoveLeft(int left, int right, const int iFactoryPos, const long long llMinPos, const vector& vPreSumDis)
{
if (right <= left)
{
return 0;
}
return vPreSumDis[right] - vPreSumDis[left] - (long long)(right - left) * (iFactoryPos - llMinPos);
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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/1466641.html

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

相关文章

计算机组成原理(12)----多处理系统

目录 1.SISD&#xff08;单指令流单数据流&#xff09; &#xff08;1&#xff09;特性 &#xff08;2&#xff09;硬件组成 2.SIMD&#xff08;单指令流多数据流&#xff09; &#xff08;1&#xff09;特性 &#xff08;2&#xff09;硬件组成 3.MISD&#xff08;多指…

【Java EE初阶二十四】servlet的深入理解

1. Servlet API 的学习 下面主要学习这三个类&#xff0c;就已经可以完成 Servlet 的大部分开发了&#xff1b; 1. Httpservlet 2. HttpServletRequest 3. HttpServletResponse 2. Httpservlet的学习 2.1 Httpservlet在tomcat的工作原理 写一个 Servlet 代码&#xff0c;往往都…

C++最佳实践之编译篇

C最佳实践之工程编译 在大型c/c工程开发中&#xff0c;往往会涉及多级CMakeLists.txt的调用&#xff0c;并且调用方式错综复杂&#xff0c;主要有以下两种方式&#xff1a; 1. 子目录中的CMakeList.txt独立生成目标&#xff0c;不作为主目标生成过程的依赖关系&#xff08;比…

Windows+Yolo3-darknet训练自己数据集并测试

WindowsYolo3-darknet训练自己的数据集并测试 一、首要条件 Windows 7下配置好VS2015OPENCV3.4.2YOLO3CUDA10.0CUDNN7.5生成darknet.exe。具体配置可参考我的博客&#xff1a;https://blog.csdn.net/wszswllnzn_/article/details/100760477 二.制作数据集 1、方法1 使用软件la…

uView组件使用

u-collapse 折叠面板 https://www.uviewui.com/components/collapse.html?ivk_sa1024320u 如果是异步加载的数据&#xff0c;最开始的 u-collapse-item是默认高度&#xff0c;&#xff0c;第一次点开的时候&#xff0c;异步数据不能撑开高度 但是如果 u-collapse-item中有内…

BUGKU-WEB 备份是个好习惯

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 看源码看提示&#xff1a;备份是个好习惯扫描目录md5弱比较 相关工具 御剑md5解密&#xff1a;https://www.somd5.com/ 解题步骤 看到的这串字符&#xff0c;有点像md5&#xff1f; d41d8cd98…

X-Rhodamine maleimide ,ROX 马来酰亚胺,实验室常用的荧光染料

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;X-Rhodamine maleimide &#xff0c;X-Rhodamine mal&#xff0c;ROX-maleimide&#xff0c;ROX 马来酰亚胺 一、基本信息 【产品简介】&#xff1a;ROX, also known as Rhodamine 101, is a product whose active …

linux0.11 源码阅读 head.s setup.s bootsect.s加载位置

从github上下载linux0.11源码 linux0.11源码 将0x10000处的代码往下复制到0开始的地址处。 移动后的内存布局如下 setup中存在gdt和idt的相关数据。此时需要用gdtr和idtr寄存器指向对应的数据。 实模式下&#xff0c;访问内存方式。最多访问1M内存。 分页模式下&…

STM32控制max30102读取血氧心率数据(keil5工程)

一、前言 MAX30102是一款由Maxim Integrated推出的低功耗、高精度的心率和血氧饱和度检测传感器模块&#xff0c;适用于可穿戴设备如智能手环、智能手表等健康管理类电子产品。 该传感器主要特性如下&#xff1a; &#xff08;1&#xff09;光学测量&#xff1a;MAX30102内置…

Java向ES库中插入数据报错:I/O reactor status: STOPPED

Java向ES库中插入数据报错&#xff1a;java.lang.IllegalStateException: Request cannot be executed; I/O reactor status: STO 一、问题问题原因 二、解决思路 一、问题 在使用Java向ES库中插入数据时&#xff0c;第一次成功插入&#xff0c;第二次出现以下错误&#xff1a…

C++种pair的初始化及与unordered_map的区别

pair的初始化及与unordered_map的区别 概述pair初始化开发环境头文件示例运行结果 与unordered_map的区别 概述 本文旨在介绍pair初始化&#xff0c;同时简述pair与unordered_map的区别。 pair初始化 pair是一个模板类&#xff0c;可以存储两个类型的数据为一个对象。 开发…

【深度学习】SSD 神经网络:彻底改变目标检测

一、说明 Single Shot MultiBox Detector &#xff08;SSD&#xff09; 是一项关键创新&#xff0c;尤其是在物体检测领域。在 SSD 出现之前&#xff0c;对象检测主要通过两阶段过程执行&#xff0c;首先识别感兴趣的区域&#xff0c;然后将这些区域分类为对象类别。这种方法虽…

js数组操作大全

目录 创建数组&#xff1a; 访问和修改数组元素&#xff1a; 数组的遍历&#xff1a; 数组的操作&#xff1a; 数组的转换&#xff1a; 创建数组&#xff1a; 使用数组字面量&#xff1a;let arr []。使用new关键字和Array构造函数&#xff1a;let arr new Array()。 访问…

【更换yarn的位置】解决yarn和nodejs不在同一盘下产生的某些命令应用失败问题

具体问题我记得是command fail什么error&#xff0c;记不太清楚了&#xff0c;文章主要写了如何替换yarn路径&#xff0c;希望可以帮助到大家。

【算法与数据结构】链表、哈希表、栈和队列、二叉树(笔记二)

文章目录 四、链表理论五、哈希表理论五、栈和队列理论5.1 单调栈 六、二叉树理论6.1 树的定义6.2 二叉树的存储方式6.3 二叉树的遍历方式6.4 高度和深度 最近博主学习了算法与数据结构的一些视频&#xff0c;在这个文章做一些笔记和心得&#xff0c;本篇文章就写了一些基础算法…

10:部署Dashboard|部署Prometheus|HPA集群

部署Dashboard&#xff5c;部署Prometheus&#xff5c;HPA集群 Dashboard部署Dashboard上传镜像到私有仓库安装服务发布服务创建管理用户查看登录的Token信息 Prometheus步骤一&#xff1a;导入所有后续需要的镜像到私有镜像仓库&#xff08;在master主机操作操作&#xff09;步…

LangChain原理学习笔记

最新越发觉得AI的发展&#xff0c;对未来是一场革命&#xff0c;LangChain已经在工程设计上有了最佳实践&#xff0c;类似于AI时代的编程模型或编程框架&#xff0c;有点Spring框架的意思。之前在LangChain上也有些最佳实践&#xff0c;所以在这里分享记录下。 LangChain解决什…

计算机网络面经-TCP三次握手一文说清

目录 说一下TCP的三次握手&#xff1f; 为什么要三次握手&#xff1f;两次行不行&#xff1f;四次呢&#xff1f; 为什么建立连接是三次握手&#xff0c;关闭连接确是四次挥手呢&#xff1f; TCP四次挥手的过程&#xff1f; 如果已经建立了连接&#xff0c;但是客户端突然出…

编译GreatSQL with RocksDB引擎

GreatSQL里也能用上RocksDB引擎 1. 前言 RocksDB 是基于Facebook 开源的一种支持事务的、高度可压缩、高性能的MyRocks存储引擎&#xff0c;特别适用于高度压缩和大容量的数据。以下是一些关键特点&#xff1a; 高性能&#xff1a; LSM 树结构使得RocksDB在写入密集型负载下表现…

苹果分拣检测YOLOV8NANO

苹果分拣&#xff0c;可以检测成熟、切片、损坏、不成熟四种类型&#xff0c;YOLOV8NANO&#xff0c;训练得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV的DNN调用&#xff0c;支持C,PYTHON 苹果分拣检测YOLOV8NANO&#xff0c;检测四种类型苹果