合并石子(动态规划)

这篇具有很好参考价值的文章主要介绍了合并石子(动态规划)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Description

在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆
.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,
记为该次合并的得分。

试设计出一个算法,计算出将 N堆石子合并成 1堆的最小得分和最大得分。

Input
数据的第 1行是正整数 N,表示有 N 堆石子, N <= 500。

第 2 行有 N 个整数,第 i个整数 ai 表示第 i 堆石子的个数, ai <= 50。

Output
输出共 2 行,第 1 行为最小得分,第 2 行为最大得分。

Sample Input
4
4 5 9 4
Sample Output
43
54

首先理解题意,笔者看到这道题时首先想到的是贪心,仔细分析后发现题上没说石子根据一定顺序来摆放,易证局部最优解不一定是问题最优解,没有贪心性质,不能用贪心

然后需要强调的是,该题是一个圆形结构

这里为了方便理解,我们先将其简化为线性结构

先看一个简单的子问题

现在一共有三堆石头,每堆石子的数量分别是3,4,11。求合并成一堆石头的最小得分。
对于这个问题,只有两种选择:
前两堆石头合并再和第三堆石头合并。
3+4=7 ——> 7 石堆变为(7, 11)
7+11=18——>18 石堆变为(18)
cost=7+18=25
后两堆石头合并再和第一堆石头合并。
4+11=15——>15 石堆变为(3,15)
3+15=18——>18 石堆变为(18)
cost=15+18=33

易看出先合并前两堆的石子的花费比较小,不同的合并方式会造成不同的得分。同时可以发现这两种方法最后一次的得分就是石头的总数

现在我们用一个数组arr[]按顺序保存每个位置的石头数量。
arr[]={3,4,11}

前缀和数组sum[i]表示前i堆石头的总和
sum[0]=3;
sum[1]=7;
sum[2]=18;

最后用一个二维数组dp[i][j]表示从第i堆到第j堆石头合并的最小分数。
1)每堆石头跟自己合并的分数都是0。
dp[0][0]=dp[1][1]=dp[2][2]=0
2)相邻两堆石头的最小合并分数只有一种可能。
dp[0][1]=3+4=7, dp[1][2]=4+11=15
3)剩下的就是不相邻石头的合并最小花费。
设一个k∈[i,j];
dp[i][j]=dp[i][k]+dp[k][j]+sum[i][j];
那么从i到j的所有花费都可以表示出来了,取一个使得dp[i][j]最小的值。
求最大花费时同理,只需将相关变量进行改变即可

最后回到原始问题,我们是一个圆形结构,此时

输入4 5 9 4,还要考虑4 4 5 9,9 4 4 5和5 9 4 4

因此我们每次都改变输入数组,最后最小取得最小,最大取得最大即可

详情可以看代码

#include<cstdio>
#include<algorithm>

using namespace std;

int dp1[505][505];//定义dp1[i][j]表示从第i堆到第j堆石子合并的最小得分 
int dp2[505][505];//定义dp1[i][j]表示从第i堆到第j堆石子合并的最大得分 
int n,maxn=0x3f3f3f3f,ans1=maxn,ans2=0;
int arr[505],sum[505];

void pc(){
	int temp=arr[0];
    for(int i=0;i<n;i++) arr[i]=arr[i+1];
    arr[n-1]=temp;
} //满足环形排列

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&arr[i]);
	}	
	for(int count=1;count<=n;count++){//4 5 9 4    5 9 4 4   9 4 4 5   4 4 5 9
//		for(int i=0;i<n;i++){
//			printf("%d ",arr[i]);
//		}
//		printf("\n");
		sum[0]=arr[0];
		for(int i=1;i<n;i++){
			sum[i]=sum[i-1]+arr[i];//前缀和数组 
		} 
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				dp1[i][j]=maxn;//求最小得分因此初始化为最大值 
				dp2[i][j]=0;//求最大得分因此初始化为最小值 
				if(i==j){//最小子问题 自己不能和自己合并因此i=j时初始化为0 
					dp1[i][j]=dp2[i][j]=0;
				}
			}
		}
		for(int k=2;k<=n;k++){//从大小为2的子问题开始求解 
			for(int i=0;i<n;i++){//起点 
				int j=i+k-1;//终点 
				if(k==2){//只有两堆石子时结果就是两堆石子相加
					dp1[i][j]=arr[i]+arr[j];
					dp2[i][j]=arr[i]+arr[j];
				}else{
					int temp=sum[j]-sum[i-1];//最后一次合并固定加上所有数之和 
					for(int t=i;t<j;t++){
						dp1[i][j]=min(dp1[i][j],dp1[i][t]+dp1[t+1][j]+temp);
						dp2[i][j]=max(dp2[i][j],dp2[i][t]+dp2[t+1][j]+temp);
					}
				}
			}
		}
//		printf("求最小\n");
//		for(int i=0;i<n;i++){
//			for(int j=0;j<n;j++){
//				printf("%d ",dp1[i][j]);
//			}
//			printf("\n");
//		}		
//		printf("求最大\n");
//		for(int i=0;i<n;i++){
//			for(int j=0;j<n;j++){
//				printf("%d ",dp2[i][j]);
//			}
//			printf("\n");
//		}		
		//最后在所有的情况中取最小值即可
		ans1=min(ans1,dp1[0][n-1]);
		ans2=max(ans2,dp2[0][n-1]);
		pc(); 		
	}
	printf("%d\n%d\n",ans1,ans2);

	return 0;
} 

读者可以将注释中的内容解开调试方便理解文章来源地址https://www.toymoban.com/news/detail-427490.html

到了这里,关于合并石子(动态规划)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 石子合并(动态规划 区间DP)+详细注释

    原题链接   活动 - AcWing 题目 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相

    2024年02月16日
    浏览(38)
  • C++动态规划经典案例解析之合并石子

    区间类型问题,指求一个数列中某一段区间的值,包括求和、最值等简单或复杂问题。此类问题也适用于动态规划思想。 如 前缀和 就是极简单的区间问题。如有如下数组: 现给定区间信息 [3,6] ,求区间内所有数字相加结果。即求如下图位置数字之和。 Tips: 区间至少包括

    2024年02月11日
    浏览(38)
  • 【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯

    分治 动态规划本篇 还差一堆 贪心 网络流 首先,怕误人子弟必须声明一下 本人很菜 (越复习越觉得完蛋了 作为一个科班研究生算法学成这样非常惭愧(跪 ,可能写的都不是很懂,很多内容打算背过去了。因为我发现好像真的有人看所以多提醒一句。。(大家就只食用目录

    2024年01月19日
    浏览(98)
  • leetcode877. 石子游戏(动态规划-java)

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/stone-game Alice 和 Bob 用几堆石子在做游戏。一共有偶数堆石子,排成一行;每堆都有 正 整数颗石子,数目为 piles[i] 。 游戏以谁手中的石子最多来决出胜负。石子的 总数 是 奇数 ,所以没有平局。 Alice 和 Bob 轮流进行,Alic

    2024年02月10日
    浏览(57)
  • 【动态规划】【C++算法】1563 石子游戏 V

    【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 动态规划汇总 几块石子 排成一行 ,每块石子都有一个关联值,关联值为整数,由数组 stoneValue 给出。 游戏中的每一轮:Alice 会将这行石子分成两个 非空行(即,左侧行和右侧行);Bob 负责计算每一

    2024年02月21日
    浏览(34)
  • 石子合并+环形石子合并+能量项链+凸多边形的划分——区间DP

    一、石子合并 (经典例题) 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合

    2024年02月19日
    浏览(46)
  • 石子合并一章通(环形石子合并,四边形不等式,GarsiaWachs算法)(内附封面)

    在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。 数据的第 1 1 1 行是正

    2024年02月14日
    浏览(39)
  • 石子合并系列问题

    石子合并问题在网上有三个版本: AcWing 282. 石子合并 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆

    2024年02月02日
    浏览(58)
  • 石子合并(区间dp)

    (1)f[l][r]表示l~r之间合并的最小代价。 (2)将l~r拆成l~k,k+1~r两份分别最优合并,再把两份合并,对于每个l,r通过枚举所有可能k探寻最优。 (3)最终目标是f[1][n],注意到长区间是由短区间递推出来的,所以由小到大枚举区间长度,再枚举起点,此时l = 起点,r = 起点 +len

    2024年02月10日
    浏览(35)
  • 21.CSS的动态圆形进度条

    2024年02月09日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包