C++前缀和算法的应用:从仓库到码头运输箱子原理、源码、测试用例

news2024/10/6 8:22:03

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频
双指针
单调双向队列

题目

你有一辆货运卡车,你需要用这一辆车把一些箱子从仓库运送到码头。这辆卡车每次运输有 箱子数目的限制 和 总重量的限制 。
给你一个箱子数组 boxes 和三个整数 portsCount, maxBoxes 和 maxWeight ,其中 boxes[i] = [ports​​i​, weighti] 。
ports​​i 表示第 i 个箱子需要送达的码头, weightsi 是第 i 个箱子的重量。
portsCount 是码头的数目。
maxBoxes 和 maxWeight 分别是卡车每趟运输箱子数目和重量的限制。
箱子需要按照 数组顺序 运输,同时每次运输需要遵循以下步骤:
卡车从 boxes 队列中按顺序取出若干个箱子,但不能违反 maxBoxes 和 maxWeight 限制。
对于在卡车上的箱子,我们需要 按顺序 处理它们,卡车会通过 一趟行程 将最前面的箱子送到目的地码头并卸货。如果卡车已经在对应的码头,那么不需要 额外行程 ,箱子也会立马被卸货。
卡车上所有箱子都被卸货后,卡车需要 一趟行程 回到仓库,从箱子队列里再取出一些箱子。
卡车在将所有箱子运输并卸货后,最后必须回到仓库。
请你返回将所有箱子送到相应码头的 最少行程 次数。
示例 1:
输入:boxes = [[1,1],[2,1],[1,1]], portsCount = 2, maxBoxes = 3, maxWeight = 3
输出:4
解释:最优策略如下:

  • 卡车将所有箱子装上车,到达码头 1 ,然后去码头 2 ,然后再回到码头 1 ,最后回到仓库,总共需要 4 趟行程。
    所以总行程数为 4 。
    注意到第一个和第三个箱子不能同时被卸货,因为箱子需要按顺序处理(也就是第二个箱子需要先被送到码头 2 ,然后才能处理第三个箱子)。
    示例 2:
    输入:boxes = [[1,2],[3,3],[3,1],[3,1],[2,4]], portsCount = 3, maxBoxes = 3, maxWeight = 6
    输出:6
    解释:最优策略如下:
  • 卡车首先运输第一个箱子,到达码头 1 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第二、第三、第四个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第五个箱子,到达码头 2 ,回到仓库,总共 2 趟行程。
    总行程数为 2 + 2 + 2 = 6 。
    示例 3:
    输入:boxes = [[1,4],[1,2],[2,1],[2,1],[3,2],[3,4]], portsCount = 3, maxBoxes = 6, maxWeight = 7
    输出:6
    解释:最优策略如下:
  • 卡车运输第一和第二个箱子,到达码头 1 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第三和第四个箱子,到达码头 2 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第五和第六个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
    总行程数为 2 + 2 + 2 = 6 。
    示例 4:
    输入:boxes = [[2,4],[2,5],[3,1],[3,2],[3,7],[3,1],[4,4],[1,3],[5,2]], portsCount = 5, maxBoxes = 5, maxWeight = 7
    输出:14
    解释:最优策略如下:
  • 卡车运输第一个箱子,到达码头 2 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第二个箱子,到达码头 2 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第三和第四个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第五个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
  • 卡车运输第六和第七个箱子,到达码头 3 ,然后去码头 4 ,然后回到仓库,总共 3 趟行程。
  • 卡车运输第八和第九个箱子,到达码头 1 ,然后去码头 5 ,然后回到仓库,总共 3 趟行程。
    总行程数为 2 + 2 + 2 + 2 + 3 + 3 = 14 。

提示:
1 <= boxes.length <= 105
1 <= portsCount, maxBoxes, maxWeight <= 105
1 <= ports​​i <= portsCount
1 <= weightsi <= maxWeight

可理解行强的解法

如果有多种运输的boxs[0,i)的方式,只需要保留行程最少的方式,且只需要记录最小行程,此值用m_vRet[i]记录。分成两步:第一步,运输box[0,j),第二步运输[j,i)。一次可以运输完成,可以看成第一步是box[0,0)。枚举i,j的时间复杂度都是O(n),总时间复杂度是O(n*n)。

利用前缀和计算[j,i)的箱子总重量

vWeightSum[i],记录了boxs[0,i)的重中立,vWeightSum[i]-vWeightSum[j]。

利用前缀和计算[i,j)需要单独下车的次数

vDownSum[i]记录[0,i)需要单独下车的次数。vDown[j]-vDownSum[i]。和前面的箱子不同,则需要单独下车。

优化枚举

m_vRet[i] = min(…,X) X=m_vRet[j]+1 + 1 + vDown[j+1,i)。 1+1 表示返程和下第一箱子,从第二个箱子起要计算要单独下。X = m_vRet[j]+1+1+vDown[i] - vDown[j+1] ,令 Y= m_vRet[j]-vDow[j+1],则X=Y + 2 + vDown[i] ,显然Y可以提前计算。每次处理完i,将Y记录到setPre中。setPre对应的索引为[left,i),如果[left,i)超量或超重,则left++,并更新setPre。

时间复杂度

枚举i,时间复杂度。二分查找setPre,时间复杂度O(logn),总时间复杂度O(nlogn)。

核心代码

class Solution {
public:
int boxDelivering(vector<vector>& boxes, int portsCount, int maxBoxes, int maxWeight) {
m_c = boxes.size();
m_vRet.resize(m_c+1);//记录boxes[0,i) 需的最小行程数
vector vWeightSum = { 0 };//箱子重量前缀和
for (const auto& v : boxes)
{
vWeightSum.emplace_back(v[1] + vWeightSum.back());
}
vector vDownSum = { 0,0 };//假定不是本车的第一个箱子,卸货需要的次数
for (int i = 1; i < m_c; i++)
{
vDownSum.emplace_back(vDownSum.back() + (boxes[i][0] != boxes[i-1][0]));
}
std::multiset setPre = { 0 }; //记录可以作为前一趟的最小行程数-vDownSum[i + 1]
int left = 0;//[left,i)是上一趟的行程
for (int i = 1; i <= m_c; i++)
{
// [left,i)为空,不会超重,也不会超量。所以无需判断是否为空
while ((i - left > maxBoxes) || (vWeightSum[i] - vWeightSum[left] > maxWeight))
{
//如果[left,i)超重或超亮
const int tmp = m_vRet[left ] - vDownSum[left+1 ];
setPre.erase(setPre.find(tmp));
left++;
}
m_vRet[i ] = *setPre.begin() + 2 + vDownSum[i] ;
if (i + 1 <= m_c)
{
setPre.emplace(m_vRet[i] - vDownSum[i + 1]);
}
}
return m_vRet.back();
}
int m_c;
vector m_vRet;
};

测试用例

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

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

int main()
{
vector<vector> boxes = { {1,1},{2,1},{1,1} };
int portsCount = 2, maxBoxes = 3, maxWeight = 3;
auto res = Solution().boxDelivering(boxes, portsCount, maxBoxes, maxWeight);
Assert(4, res);
boxes = { {1,2},{3,3},{3,1},{3,1},{2,4} };
portsCount = 3, maxBoxes = 3, maxWeight =6;
res = Solution().boxDelivering(boxes, portsCount, maxBoxes, maxWeight);
Assert(6, res);
boxes = { {2,4},{2,5},{3,1},{3,2},{3,7},{3,1},{4,4},{1,3},{5,2} };
portsCount = 5, maxBoxes = 5, maxWeight = 7;
res = Solution().boxDelivering(boxes, portsCount, maxBoxes, maxWeight);
Assert(14, res);

//CConsole::Out(res);

}

优化二:单调双向队列

原理

setPre的旧值如果大于等于新值,则被淘汰了。这意味着值是按升序排序的。移除值有两种原因:一,旧值比新值大,被淘汰。从容器尾淘汰。二,旧值超重或超过数量了,从容器头淘汰。所以用双向队列。

代码

class Solution {
public:
int boxDelivering(vector<vector>& boxes, int portsCount, int maxBoxes, int maxWeight) {
m_c = boxes.size();
m_vRet.resize(m_c+1);//记录boxes[0,i) 需的最小行程数
vector vWeightSum = { 0 };//箱子重量前缀和
for (const auto& v : boxes)
{
vWeightSum.emplace_back(v[1] + vWeightSum.back());
}
vector vDownSum = { 0,0 };//假定不是本车的第一个箱子,卸货需要的次数
for (int i = 1; i < m_c; i++)
{
vDownSum.emplace_back(vDownSum.back() + (boxes[i][0] != boxes[i-1][0]));
}
std::deque<pair<int, int>> mSumJ = { { 0,0} };
for (int i = 1; i <= m_c; i++)
{
// [left,i)为空,不会超重,也不会超量。所以无需判断是否为空
while (mSumJ.size() &&((i - mSumJ.front().second > maxBoxes) || (vWeightSum[i] - vWeightSum[mSumJ.front().second] > maxWeight)))
{
//如果[left,i)超重或超亮
mSumJ.pop_front();
}
m_vRet[i ] = mSumJ.front().first + 2 + vDownSum[i] ;
if (i + 1 > m_c)
{
continue;
}
const int iNew = m_vRet[i] - vDownSum[i + 1];
while (mSumJ.size() && (mSumJ.back().first >= iNew))
{
mSumJ.pop_back();
}
mSumJ.emplace_back(iNew, i);
}
return m_vRet.back();
}
int m_c;
vector m_vRet;
};

扩展阅读

视频课程

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

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

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

相关文章

【Git】idea提交项目到Gitee

文章目录 1. 创建Gitee仓库1. 新建仓库2. 添加描述3. 复制仓库地址 2. idea建立连接提交2.1 Create Git Repository2.2 选择要提交的根目录2.3 Commit2.4 Push2.5 提交成功 1. 创建Gitee仓库 1. 新建仓库 2. 添加描述 3. 复制仓库地址 点击右上角克隆/下载&#xff0c;复制HT…

bitbucket.org 用法

这个网站需要魔法&#xff0c;注册完成后添加厂库时间2023.10 图1 图2 第二张图 &#xff0c;不要.gitignore文件 sourcetree 1,创建前端项目 npm create vitelatest 2.打开vscode创建本地Git 看到Git代提交的文件 sourcetree&#xff0c;新建 已存在的本地厂库 提交到Git 添…

CSRF Token为什么写在Cookie中?CSRF漏洞分析

1. 什么是CSRF&#xff1f; CSRF或XSRF&#xff0c;跨站请求伪造。简单地说&#xff0c;就是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作&#xff08;如发邮件&#xff0c;发消息&#xff0c;甚至财产操作如转账和购买商品&#xff…

Java - 多进程编程(对比线程、API 操作)

目录 一、多进程编程 1.1、为什么要使用多进程编程 1.2、Java 中多进程编程的实现 1.2.1、前言 1.2.2、进程创建 1.2.3、进程等待 1.2.4、封装操作到一个工具类中 一、多进程编程 1.1、为什么要使用多进程编程 一个 .exe 文件执行以后&#xff0c;就会变成一个进程. 多…

高质量发展新引擎:智能工业操作系统助力产业升级

工业操作系统是推动制造业高质量发展的重要支撑&#xff0c;也是推动经济发展方式转变的重要手段。打造自主可控的工业实时操作系统是实现工业科技自立自强的必然要求&#xff0c;是推动高质量发展的必由之路。 基于软件定义控制的智能工业操作系统 Intewell操作系统是由科东…

【技术番外篇】国家高新技术企业 认定

第一个网站&#xff1a;高新技术企业认定管理工作网 http://www.innocom.gov.cn/gqrdw/index.shtml 多给认定机构打咨询电话&#xff0c;少走弯路 有什么不懂的地方就可以打电话咨询专业人士 http://www.innocom.gov.cn/gqrdw/c101321/201905/3b94fbc91a894bcbba97fb7125c9…

【ChatGLM2-6B】nginx转发配置

背景 好不容易把ChatGLM2-6B大语言模型部署好了&#xff0c;使用streamlit方式启动起来了&#xff0c;终于可以愉快的玩耍了&#xff0c;然后想着申请一个域名&#xff0c;使用HTTPS协议访问&#xff0c;但实践过程中&#xff0c;发现这个大语言模型的nginx转发配置还是有点小…

Swingbench 压力测试(超详细)

目录 前提需要有配置好的oracle哦 1、环境准备 2、安装Swingbench 3、造数据 4、压测 前提需要有配置好的oracle哦 1、环境准备 启动监听 lsnrctl start 启动数据库 sqlplus / as sysdba startup 创建表 CREATE TABLESPACE soe DATAFILE /u01/app/oracle/oradata/or…

重生奇迹MU游戏上格斗家挂机小技巧

重生奇迹MU作为一个独特的职业&#xff0c;重生奇迹MU游戏中的格斗家有着多种挂机技巧&#xff0c;以下是一些重生奇迹MU格斗家挂机小技巧供玩家参考&#xff1a; 1.使用幽冥光速拳 幽冥光速拳是格斗家的核心技能之一&#xff0c;可以快速消灭怪物并提高经验值。建议玩家将此…

【PX4报错】Crash dumps present on SD,vehicle needs service

报错&#xff1a; Critical: Preflight Fail: Crash dumps present on SD,vehicle needs service 解决&#xff1a; 将COM_ARM_HFLT_CHECK改为Disabled 参考&#xff1a; PX4常见解锁失败报错及解决方法

PCA降维可视化

二维 import pandas as pd import warnings warnings.filterwarnings("ignore")df pd.read_csv(data/data.csv).dropna() features df.columns[:-1] X, y df[features], df[label]from sklearn.preprocessing import MinMaxScaler # 创建MinMaxScaler对象 scaler…

论坛介绍|COSCon'23 大数据(D)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

柯桥银泰附近有学德语的地方吗,留学德语培训

01 die Garantiefr jemandem/etwas 给某人或某事的保障 Das System bietet die Garantie fr die Bauer. 02 der Gebrauch von etwas 使用某物 Wir haben den Gebrauch vom Computer gelerbt. 我们学会了使用电脑。 03 Die Geduld mit jemandem/etwas 对..的耐心 Der Lehre…

llava1.5-部署

llava1.5 ——demo部署 下载代码和权重 新建weights文件夹&#xff0c;并下载到LLaVA/weights/中。->需要修改文件名为llava-版本&#xff0c;例如llava-v1.5-7b. 运行 启动控制台 python -m llava.serve.controller --host 0.0.0.0 --port 4006启动gradio python -m…

网络拥塞控制的经济学原理

作为一个流通和兑换系统(与被发送速率兑换出的带宽不同&#xff0c;公路交通不是兑换系统&#xff0c;车辆只是单体)&#xff0c;网络传输与货币流通和兑换是一回事&#xff0c;借一些经济学术语能更深刻理解拥塞的成因和缓解以及制定拥塞控制策略&#xff0c;这是一个新视角。…

2024年浙大MPA复试可能面临的变数:权重加大

熟悉浙大mpa项目常规批复试规则的同学都知道&#xff0c;每年的复试成绩权重一般都在40%&#xff0c;这个权重对于每年复试后综合成绩的排名影响会比较大&#xff0c;按照mpa联考复试1分等于初试3分的规则&#xff0c;联考笔试成绩假如有15分差异的两个考生&#xff0c;复试成绩…

Docker 部署本地爬虫项目到服务器

笔记&#xff1a;一直想写一篇博客的&#xff0c;那就趁着周末闲暇时光记录一下。 目录 一、前提准备 二、Docker部署爬虫示例 整体梳理 1、打包构建本地项目镜像 2、在 hub 网站上 创建一个仓库。 3、将本地镜像与hub上的仓库打上标签 4、确保已登录 Dockerhub 账号 …

一键掌握多家快递信息,快递批量查询高手软件助你高效管理物流

一键掌握多家快递信息&#xff0c;快递批量查询高手软件助你高效管理物流 在当今这个高度信息化的时代&#xff0c;快递行业的发展可谓日新月异。随着网购的普及&#xff0c;如何高效、准确地掌握多家快递公司的信息&#xff0c;成为了很多消费者和管理者面临的难题。为了解决…

fastadmin笔记,fastadmin表格功能

fastadmin笔记 官方文档请到&#xff1a; https://ask.fastadmin.net/article/323.html自行查阅 1、默认有个切换功能。 浏览模式可以切换卡片视图和表格视图两种模式&#xff0c;如果不需要此功能 在该控制器对应的js 文件中添加上showToggle:false即可。 2、导出功能 …

谷歌浏览器误代码STATUS_INVALID_IMAGE_HASH如何一行代码解决

一、直入主题&#xff1a; 1.谷歌浏览器突然就不能用了&#xff0c;如下图&#xff1a; 2.如何解决 --test-type -no-sandbox 卸载浏览器重装还是一样的问题&#xff0c;目前我们的谷歌浏览器版本号&#xff1a;Chrome 已是最新版本 版本 118.0.5993.89&#xff08;正式版本&a…