【算法设计与分析】石子合并问题,对于给定n堆石子,计算合并成一堆的最小得分和最大得分。

该问题涉及将环形排列的石子合并成一堆,每次合并相邻两堆并计算得分。通过动态规划方法,计算所有可能的切割点和区间得分,找出最小得分和最大得分。程序读取input.txt文件中的数据,输出到output.txt文件中。
摘要由CSDN通过智能技术生成

一、问题描述

  在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的石子数记为该次合并的得分。试设计一种算法,计算出将n堆算法合并成一堆的最小得分和最大得分。
数据输入: 由文件input.txt提供输入数据,文件的第1行是正整数n(1≤n≤100),表示有n堆石子。第2行有n个数,分别表示每堆石子的个数。
结果输出: 将计算结果输出到文件output.txt。文件第1行的数是最小得分,第2行中的是最大得分。

二、问题分析

  链式的石子合并问题是相邻两堆之间可以合并,那么环形的和链式的区别就在于环形的相当于是链式的头尾两堆也能合并,那么我们只要解决如何在链式的基础上更换每次头和尾的问题即可,即环形的切割点n堆,有n个切割点,每次以区间长度为n的链式的进行求解。我们创建长度为2*n的数组,存放两次石子序列即可。它的最优子结构和链式一样,把当前的链式区间划分的代价达到最优即可。
  在input.txt文本的第1行输入石子堆数,第2行输入每堆石子的个数,运行程序。
在这里插入图片描述

三、运行结果

  运行程序后,打开output.txt文本,文件第1行的数是最小得分,第2行中的是最大得分。
在这里插入图片描述

四、源代码

#include<iostream>
#include<fstream>
using namespace std;
int f[100][100];
int ff[100][100];
int v[100][100];
int a[100];
int n;
int main()
{
	ifstream in("input.txt");
	ofstream out("output.txt");
	in >> n; //n堆石子
	for (int i = 1; i <= n; i++) //每堆石子的个数
	{
		in >> a[i];
		a[i + n] = a[i];
	}

	for (int i = 1; i <= n * 2; i++)
	{
		for (int j = 1; j <= n * 2; j++)
		{
			if (i != j)
				f[i][j] = 10000;
		}
	}

	for (int i = 1; i <= n * 2; i++)
	{
		for (int j = i; j <= n * 2; j++)
		{
			for (int k = i; k <= j; k++)
			{
				v[i][j] += a[k];
			}
		}
	}

	for (int len = 1; len <= n; len++)//区间划分
		for (int l = 1, r = l + len; l < n * 2 && r < n * 2; l++, r = l + len)
		{
			for (int k = l; k < r; k++)  //选择区间分割点
			{
				f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + v[l][r]);
				ff[l][r] = max(ff[l][r], ff[l][k] + ff[k + 1][r] + v[l][r]);
			}
		}
	int ans1 = 10000, ans2 = 0;
	for (int i = 1; i <= n; i++) ans1 = min(ans1, f[i][i + n - 1]); //计算最小得分
	for (int i = 1; i <= n; i++) ans2 = max(ans2, ff[i][i + n - 1]);//计算最大得分
	out << ans1 << endl;
	out << ans2;
	in.close();
	out.close();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会举重的薯片

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值