C++前缀和算法:合并石头的最低成本原理、源码及测试用例

news2025/1/10 15:36:36

本文涉及的基础知识点

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

题目

有 n 堆石头排成一排,第 i 堆中有 stones[i] 块石头。
每次 移动 需要将 连续的 k 堆石头合并为一堆,而这次移动的成本为这 k 堆中石头的总数。
返回把所有石头合并成一堆的最低成本。如果无法合并成一堆,返回 -1 。
示例 1:
输入:stones = [3,2,4,1], K = 2
输出:20
解释:
从 [3, 2, 4, 1] 开始。
合并 [3, 2],成本为 5,剩下 [5, 4, 1]。
合并 [4, 1],成本为 5,剩下 [5, 5]。
合并 [5, 5],成本为 10,剩下 [10]。
总成本 20,这是可能的最小值。
示例 2:
输入:stones = [3,2,4,1], K = 3
输出:-1
解释:任何合并操作后,都会剩下 2 堆,我们无法再进行合并。所以这项任务是不可能完成的。.
示例 3:
输入:stones = [3,5,1,2,6], K = 3
输出:25
解释:
从 [3, 5, 1, 2, 6] 开始。
合并 [5, 1, 2],成本为 8,剩下 [3, 8, 6]。
合并 [3, 8, 6],成本为 17,剩下 [17]。
总成本 25,这是可能的最小值。
提示:
n == stones.length
1 <= n <= 30
1 <= stones[i] <= 100
2 <= k <= 30

分析

dp[begin][end]记录stones[begin,end)合并后的最小得分。时间复杂度O(nnn),状态数:n*n,转移状态时间复杂度O(n)。

状态转移

假定stones[begin,end)是由stone[begin,m)和stone[m,end)合并成的,m取值范围(begin,end)。stone[begin,m)简称左堆,stone[m,end)简称右堆。

左右两堆剩余石头数之和小于kdp[begin][end] = dp[begin][m]+dp[m][end]
左右两堆剩余石头数之和等于于kdp[begin][end] = dp[begin][m]+dp[m][end]+vPreSum[begin][end],石头发生了合并
左右两堆剩余石头数之和大于于k抛弃

左右两堆剩余石头数之和大于于k

抛弃左右两堆剩余石头数之和大于于k,也可以找到最优解。

最后一轮只有k个石头,故不会超过k
倒数第二轮只有2k-1个石头,假定其范围是[i0,j0),倒数第二轮是[i1,j1), 那么[i0,j0)会合并,这时两堆石头恰好是k,故不会超过k

剩余石头数

每次合并后,石头数减少k-1。所有石头数减1,再对k-1求求余,再加1。
注意:先判断石头数是否是1,不是直接返回-1。

代码

核心代码

class Solution {
public:
	int mergeStones(vector<int>& stones, int K) {
		m_c = stones.size();
		if (1 != RemainLen(m_c,K))
		{
			return -1;
		}
		vector<int> vPreSum = { 0 };
		for (const auto& n : stones)
		{
			vPreSum.emplace_back(n + vPreSum.back());
		}
		vector<vector<int>> dp(m_c,vector<int>(m_c+1));//dp[i][j] 表示合并stones[i,j)的最小成本
		for (int len = 2; len <= m_c; len++)
		{
			for (int begin = 0; begin + len <= m_c; begin++)
			{
				const int end = begin + len;
				int iMin = INT_MAX;
				for (int m = begin + 1; m < end; m++)
				{
					const int iAdd = RemainLen(m - begin, K) + RemainLen(end - m, K);
					if (iAdd > K)
					{
						continue;
					}
					int cur = dp[begin][m] + dp[m][end];
					iMin = min(iMin, cur);
				}
				
				if (1 == RemainLen(len, K))
				{
					iMin += vPreSum[end] - vPreSum[begin];
				}
				dp[begin][end] = iMin;
			}			
		}
		return dp.front().back();
	}
	int RemainLen(int len, int k)
	{
		return 1+(len - 1) % (k - 1);
	}
	int m_c;
};

测试代码

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]);
	}
}

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








int main()
{
	vector<int> stones = { 3,5,1,2,6 };
	int k = 3;
	int res = Solution().mergeStones(stones, k);
	Assert(25, res);

	stones = { 3,2,4,1 };
	 k = 2;
	 res = Solution().mergeStones(stones, k);
	Assert(20, res); 

	stones = { 1,2,3,4,5,6,7 };
	k = 3;
	res = Solution().mergeStones(stones, k);
	Assert(49, res);

	stones = { 1,2,3,4,5,6,7 };
	k = 4;
	res = Solution().mergeStones(stones, k);
	Assert(38, res);

	stones = { 1,2,3,4,5,6,7,8,9 };
	k = 5;
	res = Solution().mergeStones(stones, k);
	Assert(60, res);
	//
	stones = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
	k = 2;
	res = Solution().mergeStones(stones, k);
	Assert(135, res);

	stones = { 9,8,7,6,5,4,3,2,1 };
	k = 3;
	res = Solution().mergeStones(stones, k);
	Assert(87, res);

	stones = { 10,9,8,7,6,5,4,3,2,1 };
	k = 4;
	res = Solution().mergeStones(stones, k);
	Assert(91, res);

	//
	stones = { 5,8,7,6,5,12,13,14,4,3,2,1,2 };
	k = 4;
	res = Solution().mergeStones(stones, k);
	Assert(155, res);

	stones = { 2,8,7,6,5,12,13,14,4,3,2,1,2 };
	k = 5;
	res = Solution().mergeStones(stones, k);
	Assert(119, res);
	//CConsole::Out(res);
}

旧版代码

 template<class T>
 void MinSelf(T* seft, const T& other)
 {
	 *seft = min(*seft, other);
 }
class Solution {
 public:
	 int mergeStones(vector<int>& stones, int k) {
		 m_k = k;
		 m_c = stones.size();
		 m_dp.assign(m_c + 1, vector<vector<int>>(m_c, vector<int>(k + 1, 1000 * 1000 * 100)));

		 vector<int> vPreSum(1);
		 for (const auto& stone : stones)
		 {
			 vPreSum.push_back(vPreSum.back() + stone);
		 }
		 for (int pos = 0; pos + 1 - 1 < m_c; pos++)
		 {
			 m_dp[1][pos][1] = 0;
		 }
		 for (int len = 2; len <= m_c; len++)
		 {
			 for (int pos = 0; pos+len <= m_c; pos++)
			 {
				 //int iEnd = pos + len - 1;
				 for (int iHeapNum = 2; iHeapNum <= k; iHeapNum++)
				 {
					 for (int iPreLen = 1; iPreLen < len; iPreLen += k - 1)
					 {
						 MinSelf(&m_dp[len][pos][iHeapNum], m_dp[iPreLen][pos][1] + m_dp[len - iPreLen][pos + iPreLen][iHeapNum - 1]);
					 }
				 }
				 m_dp[len][pos][1] = m_dp[len][pos][k] + vPreSum[pos + len] - vPreSum[pos];
			 }			
		 }		

		 return (m_dp[m_c][0][1] >= 1000 * 1000 * 100) ? -1 : m_dp[m_c][0][1];
	 }
	 
	 int m_k;
	 int m_c;
	 vector<vector<vector<int>>> m_dp;
 };

旧版代码2

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

 class Solution {
 public:
	 int mergeStones(vector<int>& stones, int k) {
		 m_k = k;
		 m_c = stones.size();
		 m_dp.assign(m_c + 1, vector<int>(m_c, ( 1000 * 1000 * 100)));

		 if ((m_c-1) % (k - 1) != 0)
		 {
			 return -1;
		 }

		 vector<int> vPreSum(1);
		 for (const auto& stone : stones)
		 {
			 vPreSum.push_back(vPreSum.back() + stone);
		 }
		 for (int pos = 0; pos + 1 - 1 < m_c; pos++)
		 {
			 m_dp[1][pos] = 0;
		 }
		 for (int len = 2; len <= m_c; len++)
		 {
			 for (int pos = 0; pos+len <= m_c; pos++)
			 {
				 for (int iPreLen = 1; iPreLen < len; iPreLen += k - 1)
				 {
					 MinSelf(&m_dp[len][pos], m_dp[iPreLen][pos] + m_dp[len - iPreLen][pos + iPreLen]);
				 }
				 if ((len-1) % (k - 1) == 0)
				 {
					 m_dp[len][pos] +=  vPreSum[pos + len] - vPreSum[pos];
				 }
			 }			
		 }		

		 return (m_dp[m_c][0] >= 1000 * 1000 * 100) ? -1 : m_dp[m_c][0];
	 }
	 
	 int m_k;
	 int m_c;
	 vector<vector<int>> m_dp;
 };

旧版代码三

class Solution {
public:
int mergeStones(vector& stones, int k) {
m_c = stones.size();
if (0 != (m_c - 1) % (k-1))
{
return -1;
}
vector vPreSum(1);
for (const auto& n : stones)
{
vPreSum.emplace_back(vPreSum.back() + n);
}
vector<vector> vLenBegin(m_c + 1, vector(m_c));
for (int len = k; len <= m_c; len++)
{
for (int begin = 0; begin + len - 1 < m_c; begin++)
{
int iMaxPreScore = INT_MAX;
for (int lLen = 1; lLen < len; lLen += (k - 1))
{
int rLen = len - lLen;
iMaxPreScore = min(iMaxPreScore, vLenBegin[lLen][begin] + vLenBegin[rLen][begin + lLen]);
}
if (0 == (len - 1) % (k - 1))
{
iMaxPreScore += vPreSum[begin + len] - vPreSum[begin];
}
vLenBegin[len][begin] = iMaxPreScore ;
}
}
return vLenBegin.back().front();
}
int m_c;
};

扩展阅读

视频课程

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

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

相关文章

asp.net企业招聘管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio计算机毕业设计

一、源码特点 asp.net 企业招聘管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语 言开发 asp.net企业招聘管理系统 二、功…

SpringBoot常见异步编程,你会多少?

微信公众号访问地址&#xff1a;SpringBoot常见异步编程&#xff0c;你会多少&#xff1f; 近期热推文章&#xff1a; 1、springBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表; 2、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据; 3、基于Redis…

线性代数2:梯队矩阵形式

图片来自 Europeana on Unsplash 一、前言 欢迎阅读的系列文章的第二篇文章&#xff0c;内容是线性代数的基础知识&#xff0c;线性代数是机器学习背后的基础数学。在我之前的文章中&#xff0c;我介绍了线性方程和系统、矩阵符号和行缩减运算。本文将介绍梯队矩阵形式&#xf…

2023年中国养殖渔船产业链、市场规模及发展趋势分析[图]

养殖渔船行业是指涉及水产养殖活动的渔船制造、运营和相关服务的产业。这个行业将渔船和水产养殖业结合起来&#xff0c;包括生产和维护用于养殖水域中养殖活动的各种船只&#xff0c;如养殖网船、渔业养殖船、水产养殖工作船等。 养殖渔船行业产业链 资料来源&#xff1a;共研…

2023年中国车用冲压模具行业特征、竞争现状及行业市场规模分析[图]

汽车冲压件模具具有尺寸大、型面复杂、精度要求高等特点&#xff0c;属于技术密集型产品。汽车冲压模具能快速精密地把材料直接加工成零件或半成品并通过焊接、铆接、拼装等工艺装配成零部件&#xff0c;冲压模具的设计开发和加工能力对汽车冲压零部件产品总制造成本、质量及性…

SpringBoot(二)集成 Quartz:2.5.4

Quartz是一个广泛使用的开源任务调度框架&#xff0c;用于在Java应用程序中执行定时任务和周期性任务。它提供了强大的调度功能&#xff0c;允许您计划、管理和执行各种任务&#xff0c;从简单的任务到复杂的任务。 以下是Quartz的一些关键特点和功能&#xff1a; 灵活的调度器…

海外问卷调查是不是真的能赚钱?

海外问卷调查是不是真的能赚钱&#xff1f;我来告诉你&#xff0c;我在橙河网络这家公司干了两年半的问卷调查&#xff0c;可以明确地告诉你&#xff1a;海外问卷调查确实可以赚钱&#xff0c;真的&#xff01; 海外问卷调查这个项目&#xff0c;在国内已经存在了很长时间&…

KVM动态在线迁移实操笔录

环境介绍 一台NFS&#xff08;192.168.184.132&#xff09; 一台KVM-a&#xff08;192.168.184.133&#xff09; 一台KVM-b&#xff08;192.168.184.134&#xff09; NFS配置 [rootlocalhost ~]# setenforce 0 //关闭selinux [rootlocalhost ~]# service iptables stop [root…

电子元器件网络变压器(网络滤波器 ̖ 脉冲变压器)的EMI产生原因

Hqst华强盛&#xff08;盈盛电子&#xff09;导读&#xff1a;网络变压器&#xff08;网络滤波器 ̖ 脉冲变压器&#xff0c;以下称网络变压器&#xff09;在工作过程中会产生电磁场&#xff0c;这可能会导致电磁干扰&#xff08;EMI&#xff09;。EMI会影响设备的性能和可靠性…

基于Java的图书商城管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

基于Java的图书馆借阅管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

设计模式:模板模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

简介&#xff1a; 模板模式&#xff0c;它是一种行为型设计模式&#xff0c;它定义了一个操作中的算法的框架&#xff0c;将一些步骤延迟到子类中实现&#xff0c;使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 通俗地说&#xff0c;模板模式就是将某一行…

微信小程序数据交互------WXS的使用

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.数据库连接 数据表结构&#xff1a; 数据测式&#xff1a; 2.后台配置 pom.xml <?xml version&quo…

重磅发布!RflySim Cloud 智能算法云仿真平台亮相,助力大规模集群算法高效训练

RflySim Cloud智能算法云仿真平台&#xff08;以下简称RflySim Cloud平台&#xff09;是由卓翼智能及飞思实验室为无人平台集群算法验证、大规模博弈对抗仿真、人工智能模型训练等前沿研究领域研发的平台。主要由环境仿真模块、物理效应计算模块、多智能体仿真模块、分布式网络…

Python安装使用graphviz经验,Format: “png“ not recognized

Graphviz 是一款由 AT&T Research 和 Lucent Bell 实验室开源的可视化图形工具&#xff0c;可以很方便的用来绘制结构化的图形网络&#xff0c;支持多种格式输出。Graphviz 输入是一个用 dot 语言编写的绘图脚本&#xff0c;通过对输入脚本的解析&#xff0c;分析出其中的点…

摆闸机的应用领域和性能特点

摆闸机是一种常用于门禁控制和人员管理的设备&#xff0c;它具有以下应用领域和性能特点&#xff1a; 应用领域&#xff1a; 门禁控制&#xff1a;摆闸机可以用于各种场合的门禁控制&#xff0c;如小区、写字楼、学校、医院等。人员管理&#xff1a;摆闸机可以用于管理进出人…

最优化:建模、算法与理论(最优性理论2

5.7 约束优化最优性理论应用实例 5.7.1 仿射空间的投影问题 考虑优化问题 min ⁡ x ∈ R n 1 2 ∣ ∣ x − y ∣ ∣ 2 2 , s . t . A x b \min_{x{\in}R^n}\frac{1}{2}||x-y||_2^2,\\ s.t.{\quad}Axb x∈Rnmin​21​∣∣x−y∣∣22​,s.t.Axb 其中 A ∈ R m n , b ∈ R m …

【软考-中级】系统集成项目管理工程师-人力资源管理历年案例

持续更新。。。。。。。。。。。。。。。 目录 2019 下 试题三(20分)背诵整理1. 冲突管理的6种方法2. 获取项目人力资源的依据 系列文章 2019 下 试题三(20分) 阅读下列说明&#xff0c;回答问题 1至问题 3&#xff0c;将解答填入答题纸的对应栏内     某公司承接了一个软件…

Java BigDecimal计算及转换

BigDecimal应用汇总 1、负数转正数 a.abs(); 相当于&#xff1a;绝对值2、加法 a.add(b)3、减法 a.subtract(b) 相当于&#xff1a;a-b4、乘法 a.multiply(b)5、除法 a.divide(b) 相当于&#xff1a;a/b6、处理小数 BigDecimal.setScale()方法用于格式化小数点 setScale…