动态规划——石子合并问题

C++动态规划经典案例解析之合并石子 区间类型问题,指求一个数列中某一段区间的值,包括求和、最值等简单或复杂问题。此类问题也适用于动态规划思想。如前缀和就是极简单的区间问题。现给定区间信息[3,6],求区间内所有数字相加结果。即求如下图位置数字之和。区间至少包括2个属性,起始端和结束端,求和范围包含左端和右端数字。累加数组中0~6区间的值s1。累加数组中0~2区间的值s2。将s1中的值减去s2中的值。得到最终结果。如果对任意区间的求解要求较频繁,会存在大量的重复计算。如分别求区间[2,5]和[1,5]之和时,分析可知区间。 阅读详情

石子合并问题分三类:

1、任意合并
2、相邻的才能合并且排成直线
3、相邻的才能合并且围成圈

1、贪心即可解决

合并果子(贪心题)

2、直线型

合并石子直线型
对于区间dp问题,我们先要把它细分为区间
我们可以这样定义dp数组
dp[i][j]的意义是,合并第i个石子到第j个石子的最小(最大)得分
那就开始找吧

int findMin(int l, int r)
{
	if(dp[l][r])
	return dp[l][r];
	if(l == r)
	return 0;
	int _min = MAX;//0x3f3f3f3f
	int s = 0;
	for(int i = l; i <= r; i++)
	s += a[i];//区间总和,最后一下合并 
	for(int i = l; i < r; i++)
	_min = min(_min, findMin(l, i) + findMin(i+1, r) + s);//将区间细分
	dp[l][r] = _min;
	return dp[l][r];
}

s的意义是找到l到r区间内所有石子的分之和,用于把最后两大堆合起来
AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int dp[107][107];
int a[107];
const int MAX = 0x3f3f3f3f;

int findMin(int l, int r)
{
	if(dp[l][r])
	return dp[l][r];
	if(l == r)
	return 0;
	int _min = MAX;
	int s = 0;
	for(int i = l; i <= r; i++)
	s += a[i];//区间总和,最后一下合并 
	for(int i = l; i < r; i++)
	_min = min(_min, findMin(l, i) + findMin(i+1, r) + s);
	dp[l][r] = _min;
	return dp[l][r];
}

int findMax(int l, int r)
{
	if(dp[l][r])
	return dp[l][r];
	if(l == r)
	return 0;
	int _max = -1;
	int s = 0; 
	for(int i = l; i <= r; i++)
	s += a[i];//区间总和,最后一下合并 
	for(int i = l; i < r; i++)
	_max = max(_max, findMax(l, i) + findMax(i+1, r) + s);
	dp[l][r] = _max;
	return dp[l][r];
}
int main()
{
	while(scanf("%d", &n) != EOF)
	{
		memset(dp,0,sizeof(dp));
		for(int i = 1; i <= n; i++)
			cin >> a[i];
		cout << findMin(1,n) << " ";
		memset(dp,0,sizeof(dp));
		cout <<findMax(1,n) << endl;
	}
}

注:思路来源于集训队冷包学长,谢谢学长

3、围成圈

合并石子环形
这时我们dp数组的意义改变了
dp[i][j]表示从第i个元素开始往后走j个元素的最小(最大)值
因为如果五个元素的话
dp[1][5]
dp[2][5]
…
dp[5][5]
这几个的值大概率是不一样的

如何解决圈的问题呢?

思路一:

强行给他围成圈
运用取模运算的方法

for(int i = 2; i <= n; i++)//走几步 
		{
			for(int j = 1; j <= n; j++)//从哪开始 
			{
				dp_max[j][i] = -1;
				dp_min[j][i] = MAX;
				for(int k = 1; k < i; k++)
				{
					dp_max[j][i] = max(dp_max[j][i], dp_max[j][k] + dp_max[(j+k-1) % n + 1][i - k] + cost(j, i));
					dp_min[j][i] = min(dp_min[j][i], dp_min[j][k] + dp_min[(j+k-1) % n + 1][i - k] + cost(j, i));
				}
			}
		}

(j+k-1)%n+1 从1到n又马上接上1,完美地避开了0

思路二:

开两倍数组,将元素按原来的顺序复制在后面
比如
样例 :
3
1 2 3
我们这样存数据
1 2 3 1 2 3
这样就围成了圈,是不是很棒?

for(int i = 1; i <= n; i++)
		{
			scanf("%d", &a[i]);
			a[i + n] = a[i];//在这里实现
			dp_min[i][i] = 0;
			dp_min[i + n][i + n] = 0; 
		}

然后应该不太难了
这里是dp部分:

for(int len = 2; len <= n; len++)//走几步 
		{
			for(int i = 1; len + i - 1 <= 2 * n; i++)//从哪开始 
			{
				int j = len + i - 1;
				for(int k = i; k < j; k++)
				{
					dp_min[i][j] = min(dp_min[i][j], dp_min[i][k] + dp_min[k + 1][j] + cost[j] - cost[i - 1]);
					dp_max[i][j] = max(dp_max[i][j], dp_max[i][k] + dp_max[k + 1][j] + cost[j] - cost[i - 1]);
				}
			}
		}

然后AC啦:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int dp_max[207][207];
int dp_min[207][207];
int cost[207];
int a[203];
const int MAX = 0x3f3f3f3f;

int main()
{
	while(scanf("%d", &n) != EOF)
	{
		memset(dp_min, MAX, sizeof(dp_min));
		memset(dp_max, 0, sizeof(dp_max));
		for(int i = 1; i <= n; i++)
		{
			scanf("%d", &a[i]);
			a[i + n] = a[i];
			dp_min[i][i] = 0;
			dp_min[i + n][i + n] = 0; 
		}
		cost[0] = 0;
		
		for(int i = 1; i <= 2 * n; i++)//为了后面方便用前缀和
		cost[i] = cost[i - 1] + a[i];
		
		for(int len = 2; len <= n; len++)//走几步 
		{
			for(int i = 1; len + i - 1 <= 2 * n; i++)//从哪开始 
			{
				int j = len + i - 1;
				for(int k = i; k < j; k++)
				{
					dp_min[i][j] = min(dp_min[i][j], dp_min[i][k] + dp_min[k + 1][j] + cost[j] - cost[i - 1]);
					dp_max[i][j] = max(dp_max[i][j], dp_max[i][k] + dp_max[k + 1][j] + cost[j] - cost[i - 1]);
				}
			}
		}
		int ans_min = MAX;
		int ans_max = -1;
		for(int i = 1; i <= n; i++)
		{
			ans_min = min(ans_min, dp_min[i][i+n-1]);
			ans_max = max(ans_max, dp_max[i][i+n-1]);
		}
		cout << ans_min << " " << ans_max << endl;
	}
	return 0;
}
2.4动态规划—石子合并问题 1. 问题描述 设有 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;如果第二步 阅读详情

相关推荐

动态规划石子合并问题

问题描述:在一个圆形操场的四周摆放着n堆石子,现要将石子有次序的合并成一堆。每次只能选择相邻的2堆石子合并成新的一堆,并将新的一对石子数记为该次合并的得分。 求 最小值和最大值 in: 4 4 4 5 9out: 43 541.首先考虑 石子是环形摆放 所以可以 将数组存放成 4 4 5 9 4 4 5 2.然后从局部最优求到全局最优其中采用2个数组来储存 运算过程用到的数据

haoyuwhyt的博客 6354

石子合并问题(动态规划)

动态规划 石子合并问题

m0_52124992的博客 2万+

石子合并的动态规划问题

题目大概都是这样的:   设有N堆沙子排成一排,其编号为1,2,3,…,N(N dp的方程很显然: 区间DP dp[i][j]=min(dp[i][k]+dp[k+1][j]+cost[i][j])   i 复杂度 N^3 这同时也是一个四边形优化DP的标准形式,对于i到j段的最优值s[i][j]满足:  s[i][j-1] 可以减小枚举范围,复杂度N^2

码代码的猿猿 2154

【动态规划】之石子合并问题

在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。请设计一个程序,计算出将N堆石子合并成一堆的最小得分和最大得分。

weixin_67774087的博客 3674

动态规划——区间dp [石子合并]

动态规划(dp)是一种通过将问题分解为子问题,并利用已解决的子问题的解来求解原问题的方法。适用于具有重叠子问题和最优子结构性质的优化问题。通过定义状态和状态转移方程,动态规划可以在避免重复计算的同时找到问题的最优解,是一种高效的求解方法,常用于解决各种问题,如最短路径、背包问题、序列比对等。区间dp是一种dp的应用,用于解决涉及区间的问题。它将问题划分为若干个子区间,并通过定义状态和状态转移方程来求解每个子区间的最优解,最终得到整个区间的最优解。

小天狼星_布莱克 的博客 3609

石子合并问题的 动态规划解法

王晓东版 //--石子合并问题 /*问题描述:在一个圆形操场的四周摆放着n堆石子,先要将石子有序的合并为一堆。规定每次只能选相邻的石子合并成一堆,并将新一堆的石子数 记录为该次合并的得分。试设计一个算法,记录n堆石子合并的最大和最小得分。 数据输入:由文件input.txt输入,第一行是正整数n,表示有n堆石子。第二行有n个正整数,分别表示每堆石子的个数, 结果输出:将计算结果输出到文件output.txt中,文件中第一行是最小得分,第二行是最大得分 解题思路:类似于矩阵连乘问题,可以用动态规划的方法来解决: (1)定义一个n*n的数组A来存储合并石子的最小合并方式,由一开始的只有两堆石子要合并慢慢向上递归得到n堆石子合并的最小得分。 (2)定义另一个于A同秩的矩阵B来存储各个合并中间的剖分 */

租用游艇问题 石子合并问题 动态规划实验

实验名称: 动态规划 一、实验预习 1、实验目的 1. 理解并掌握动态规划方法的设计思想; 2. 提高应用动态规划方法解决问题和设计算法的能力; 3. 通过编程实现租用游艇问题和石子合并问题,进一步理解动态规划方法解题的四个基本步骤。 2、实验内容 1. 租用游艇问题:长江游艇俱乐部在长江上设置了 n 个游艇出租站 1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站 i ...

QENGFENG的博客 3175

DeepSeek提示词实战:从零到百的AI角色扮演指南(附100+场景模板)

本文提供了一份详尽的DeepSeek提示词实战指南,重点讲解AI角色扮演的核心技巧。通过“角色扮演四要素法”和五大核心场景模板,帮助用户从零开始掌握如何设计高质量提示词,有效提升AI输出的深度与精度,并附赠100+实用场景模板供参考。

weixin_29305337的博客 579

石子合并问题动态规划

问题描述: 有 n 堆石子堆放在路边围成一个圆,现要将石子有序地合并成一堆,规定每次只能移动相邻的两堆石子合并,合并花费为新合成的一堆石子的数量。求将这 N 堆石子合并成一堆的总花费(最小或最大)。 源代码: package suanfa; public class 石子合并 { public static int sum(int x[],int i,int j) { int sum=0; f...

Shipshape的博客 1601

新手必看:LiteRadio 2c SE遥控器从开箱到飞行的完整指南(附常见问题解答)

本文为新手提供LiteRadio 2c SE遥控器的完整使用指南,涵盖从开箱到首飞的20个关键步骤。详细介绍了遥控器的功能设置、与无人机的对频技巧以及首飞注意事项,帮助用户快速掌握飞行控制,避免常见错误。特别适合无人机初学者阅读。

weixin_29209801的博客 378

Spring Authorization Server实战:从零搭建OAuth2.1授权中心(含数据库改造)

本文详细介绍了如何从零开始使用Spring Authorization Server搭建符合OAuth2.1规范的授权中心,并完成关键的数据库持久化改造。内容涵盖微服务架构下的统一认证需求、基础配置、数据库表设计、高级特性(如令牌自定义、性能优化)以及与现有系统(如SSO、Gateway网关)的集成实战,为构建生产级授权服务提供完整指南。

weixin_29315091的博客 253

动态规划思想:石子合并问题

描述: 在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。 规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。 试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。 开始以为通过贪心算法可能很快解决问题,可是是行不通的。 ...

721

DFRobot MGC3130电容式手势传感器库深度解析

电容式近场感应(Electric Near Field Sensing)是一种非接触、抗干扰的三维空间感知技术,其原理基于人体介电特性对高频电场的扰动响应,具备低功耗、高鲁棒性与零物理接触等核心优势。该技术广泛应用于医疗人机交互、工业HMI、智能家电等对可靠性与环境适应性要求严苛的嵌入式场景。DFRobot_MGC3130库正是面向Microchip MGC3130芯片的工程化实现,封装了I²C驱动、ASU硬件加速调度及多层抽象API,支持手势识别、触控检测与接近唤醒等功能动态切换。结合电容式近场感应与嵌入

weixin_34620658的博客 549

动态规划之石子合并问题(Circle版)

问题描述 简单说下结果是怎么来的: 43=(4+4) + (4+4+5) + (4+4+5+9) 53=(9+5) + (9+5+4) + (9+5+4+4) 算法分析 这个问题和普通的石子合并问题不同,简单的石子合并问题采用的是将石子线性排列并合并,但是这个问题要求石子按照圆圈排列,所以首尾两个石子是能够合并的。 这就不由得引起我们的思考,我们怎么才能让首尾也相邻呢? 方法有两个: 1.遍历数组的时候将索引从0到2*n之间遍历,但是每次都要%n来求真实索引; 2.直接扩展数组,将两个一模一样的数字连接在

weixin_44755413的博客 2667

mysql 计算不同胜率的活跃玩家的次日,3日,7日留存率

它根据每天的日期(logymd)和最高段位(max_rank)、胜率段落(win_rate_segment)进行分组,并计算总玩家人数(total_players)、第二天的留存人数(next_day_players)、第三天的留存人数(day3_players)和第七天的留存人数(day7_players)。注意:不是新手留存,是段位活跃玩家留存;最终的结果则是将留存数据进行展示,按照日期(date)、最高段位(rank_level)、胜率段落(win_rate_segment)进行排序。

weixin_42698221的博客 1834

别再手动填数据了!Vivado里用.coe文件给ROM IP核预装数据的保姆级教程

本文详细介绍了在Vivado中使用.coe文件为ROM IP核预装数据的全流程教程,包括文件格式规范、数据转换技巧和Vivado配置指南。通过自动化数据加载,开发者可以显著提升FPGA开发效率,避免手动输入错误,适用于查找表、波形存储等多种应用场景。

weixin_33377602的博客 337

动态规划——环形石子合并问题

规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。从后向前遍历,考虑所有可能的合并点,并通过比较不同分割点的得分来更新 dpmin 和 dpmax。最小得分:对于每个区间 [i, j],找到所有可能的分割点 k,计算通过 k 分割的得分,并更新 dpmin[i][j]。第二行有n个数,分别表示每堆石子的个数。输出结果:遍历 dpmin 和 dpmax 数组,找到所有可能起始点的最小和最大得分,并输出。

m0_73968680的博客 1090

双目相机立体匹配算法概述(含Python代码)

立体匹配任务是计算机视觉中的一个重要问题,旨在从一对具有相同场景的图像中估计每个像素的视差(disparity)。本文对现有的传统算法和深度学习算法进行了综述,以便于各位选择合适的立体匹配算法用于深度估计或三维建模。

m0_59257547的博客 8291

石子合并问题java_动态规划求石子合并问题

1.问题描述在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。2.动态规划or贪心算法动态规划:用来求解最优性质的解,将原问题划分为若干个子问题,先求解子问题的解,由子问题的解求出原问题的解。这些子问题往往不互相独立,所以我们用一个表...

weixin_29085151的博客 1103

手把手教你完成基于matlab的路面裂缝检测系统设计

裂缝是路面病害最早的形态之一,只有在裂缝出现的早期进行维护,才能有效地提高公路的使用寿命。因此,路面裂缝的检测识别系统对于提升公路质量有着重大的意义。首先,对路面裂缝图像进行相应的预处理,目的是减小环境因素的影响,消除无用的噪点。然后提取目标图像特征,判断路面裂缝类型,标记出路面裂缝的位置。最后通过设计的 GUI 界面来集成各个关键步骤,显示所得到的试验结果。仿真结果表明,设计的路面裂缝检测识别系统是高效可行的。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1216

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

动态规划解决石子合并问题(C语言)

石子合并问题:在一个圆形操场的四周摆放着n堆石子。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。

SunAo42的博客 1562

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【动态规划】石子合并问题

题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,合并的花费为这相邻两堆之和 试设计出1个算法,计算出将N堆石子合并成1堆的最小花费和最大花费. 输入输出格式 输入格式: 数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数. 输入示例 4 4 4 5 9 输出示例 43 54 以下内容参考博客:区间dp问题 区间DP概念 区间DP是线性DP的扩展,分阶段地划分问题,与阶段中元

WR的博客 2090

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【算法设计与分析】动态规划解决石子合并问题(课程设计)

动态规划算法是计算机算法设计中的一个重要算法,通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推的方式去解决,石子合并问题作为典型算例,能够彰显动态规划算法特征 针对石子合并问题,本文利用动态规划算法寻求石子合并时的最大,最小得分,选择相邻的两堆石子堆进行合并,其最终花费的代价与石子堆的排列顺序有关。根据其重叠子问题建立状态转移方程,利用程序进行求解。算例结果显示:将4堆石子合并成一堆,每堆的石子个数分别是4,4,5,9,合并的代价最小得分为43,最大得分为54

qq_44871101的博客 1万+
上一篇: 动态规划——最长公共子序列LCS
下一篇: 动态规划——有顺序的背包问题
Linda_yezi_coder
博客等级 码龄7年 20粉丝 88原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值