1019: 堆石子 2016年中南大学研究生复试机试题
题目描述
在一片沙滩上摆放着 n堆石子。 现要将石子有次序地合并成一堆。 规定每次选2 堆相邻石子合并成新的一堆,合并的费用为新的一堆石子数。试设计一个算法,计算出将 n堆石子合并成一堆的最小总费用。
输入
多组数据
输入数据第1行有1个正整数 n(1≤n≤300),表示有 n堆石子,每次选2堆石子合并。第2行有 n个整数, 分别表示每堆石子的个数(每堆石子的取值范围为[1,1000]) 。
输出
数据输出为一行, 表示对应输入的最小总费用。
样例输入
7
45 13 12 16 9 5 22
样例输出
313
解题思路
这题比较我觉得比较难想,可以用暴力, 但是我觉得暴力肯定会被卡掉,百度了一个算法叫GarsiaWachs算法。时间复杂度为O(n^2)。
它的步骤如下:
设序列是stone[],从左往右,找一个满足stone[k-1] <= stone[k+1]的k,找到后合并stone[k]和stone[k-1],再从当前位置开始向左找最大的j,使其满足stone[j] > stone[k]+stone[k-1],插到j的后面就行。一直重复,直到只剩下一堆石子就可以了。在这个过程中,可以假设stone[0]和stone[n+1]是正无穷的。
举个例子:
186 64 35 32 103
因为35<103,所以最小的k是4,我们先把35和32删除,得到他们的和67,并向前寻找一个第一个超过67的数,把67插入到他后面,得到:186 67 64 103,
现在由5个数变为4个数了,继续:因为67<103 ,所以k=3 ,删除67和64, 得到它们的和131 ,然后插入186后面,得到:186 131 103,
然后找到 k=2(别忘了,设stone[0]和stone[n+1]等于正无穷大)得到:234 186,最后得到420。最后的答案呢?就是各次合并的重量之和,即420+234+131+67=852。
基本思想是通过树的最优性得到一个节点间深度的约束,之后证明操作一次之后的解可以和原来的解一一对应,并保证节点移动之后他所在的深度不会改变。具体实现这个算法需要一点技巧,精髓在于不停快速寻找最小的k,即维护一个“2-递减序列”朴素的实现的时间复杂度是O(n*n),但可以用一个平衡树来优化,使得最终复杂度为O(nlogn)。
AC Code
#include<iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 300 + 4;
int size=0, stone[MAXN];
void Erase(int first, int last){// delete elements in [first last)int t=last-first;for(int i=last; i<=size; ++i)stone[i-t]=stone[i];size-=t;
}
void Insert(int pos, int value){for(int i=size; i>=pos; --i)stone[i+1]=stone[i];stone[pos]=value;size+=1;
}
int main(){freopen("C:\\Users\\Ambition\\Desktop\\in.txt","r",stdin);int n;while(~scanf("%d", &n)){size=n+1, stone[0]=INF, stone[n+1]=INF-1;for(int i=1; i<=n; ++i) scanf("%d", &stone[i]);int heap=n, tmp, i, j, k, min_cost=0;while(heap>1){i=1;while(stone[i-1]>stone[i+1]) ++i;tmp=stone[i-1]+stone[i], min_cost+=tmp;k=i-1;Erase(k, k+2);j=k-1;while(stone[j]<tmp) --j;Insert(j+1, tmp);--heap;}printf("%d\n", min_cost);} return 0;
}
参考博客
1019: 堆石子 2016年中南大学研究生复试机试题相关推荐
- 2016年中南大学研究生复试机试题(1015~1019)
目录: **A:第几天 B:加油站 C:序列求平均 D:士兵排阵 ** A:第几天 http://39.106.164.46/problem.php?id=1015 思路: 分闰年和非闰年讨论即可. ...
- 1028: 安全路径(2014年中南大学研究生复试机试题 )
1028: 安全路径 时间限制: 1 Sec 内存限制: 128 MB 提交: 228 解决: 96 [提交][状态][讨论版] 题目描述 卫斯理小说经常提及外星人,比如蓝血人. 在土星星球有很多 ...
- 2018年 中南大学研究生复试机试题(1025~ 1028)
目录: A:最短距离 B:a + b问题 C:逃离迷宫 D:可乐 A:最短距离 http://39.106.164.46/problem.php?id=1025 思路: 设小王的坐标为(x1 + u1 ...
- 2014年中南大学研究生复试机试题(字符串、基础dp、最短路)
A.B.C题很简单. D.最大连续子序列 思路: 求最大连续子序列的值以及左右端点. 那么我们记录连续和值为s,最值为maxx,只有maxx改变时才改变左右端点,考虑记录l,r,即当前的区间端点. 那 ...
- 1004: 惠民工程 (2013年中南大学研究生复试机试 )
1004: 惠民工程 时间限制: 1 Sec 内存限制: 128 MB 提交: 404 解决: 81 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 市政府"惠民工程&q ...
- 中南大学2019研究生复试机试题
中南大学2019研究生复试机试题 机试题共六题 1.选球问题 题目描述 输入 输出 样例输入 样例输出 解决代码 2.模拟出入栈游戏 题目描述 输入 输出 样例输入 样例输出 解决代码 3.爬楼梯游戏 ...
- 2013年中南大学研究生复试机试(1000~1004)
目录: A:回文串问题 B:水仙花数 C:安全密码 D:最少钱币数 E:惠民工程 A:回文串问题 http://39.106.164.46/problem.php?id=1000 思路: 判断是否为回 ...
- 1028-可乐(中南大学18年研究生复试机试题)
题目描述 猪年快乐!在这个快乐的日子里我们当然要去超市买可乐喝啦! 现在超市有n种可乐,第 i 种可乐的价格为C[i] ,体积为 2i-1 毫升,每种可乐都是无限供应的 ,现在你想买至少 L毫升的可乐 ...
- 华科研究生复试机试题代码堆积供以后参考
#include "stdafx.h" #include <cstdio> #include <cstring> using namespace std;# ...
最新文章
- yudian温控表a1温度怎么补偿_冰箱冷藏温度多少合适 冰箱冷藏温度怎么调节 看完这篇你就有答案 冰箱...
- FEMS:微生物群落生态学数据挖掘的R包microeco
- mysql having子句_mysql having子句学习
- java sort算法名称_快速排序算法(Quick Sort)(java)
- 【 FPGA 】使用状态机设计一个ADC采样控制电路
- hbuilder ios 打包失败,无法导入p12证书的解决方案
- STM32F030 ADC1的DMA采样问题
- mybatis入门配置——基于xml配置
- SQL Server2005 使用FOR XML选项进行字符串的串联聚合
- 前端程序员容易忽视的一些基础知识
- LeetCode LCP 22. 黑白方格画
- Java中String转Long方式及注意事项
- 边框回归的损失函数_CVPR 2019:精确目标检测的不确定边界框回归
- 嵌入式语音识别系统之电路设计原理
- mitmproxy监听数据请求并处理数据
- 小米MiSans字体安装教程
- text/plain
- java期末心得,java期末小结
- python 四则运算
- 测试杀毒软件的一段代码![无毒无害]