题目描述

在一片沙滩上摆放着 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年中南大学研究生复试机试题相关推荐

  1. 2016年中南大学研究生复试机试题(1015~1019)

    目录: **A:第几天 B:加油站 C:序列求平均 D:士兵排阵 ** A:第几天 http://39.106.164.46/problem.php?id=1015 思路: 分闰年和非闰年讨论即可. ...

  2. 1028: 安全路径(2014年中南大学研究生复试机试题 )

    1028: 安全路径 时间限制: 1 Sec  内存限制: 128 MB 提交: 228  解决: 96 [提交][状态][讨论版] 题目描述 卫斯理小说经常提及外星人,比如蓝血人. 在土星星球有很多 ...

  3. 2018年 中南大学研究生复试机试题(1025~ 1028)

    目录: A:最短距离 B:a + b问题 C:逃离迷宫 D:可乐 A:最短距离 http://39.106.164.46/problem.php?id=1025 思路: 设小王的坐标为(x1 + u1 ...

  4. 2014年中南大学研究生复试机试题(字符串、基础dp、最短路)

    A.B.C题很简单. D.最大连续子序列 思路: 求最大连续子序列的值以及左右端点. 那么我们记录连续和值为s,最值为maxx,只有maxx改变时才改变左右端点,考虑记录l,r,即当前的区间端点. 那 ...

  5. 1004: 惠民工程 (2013年中南大学研究生复试机试 )

    1004: 惠民工程 时间限制: 1 Sec  内存限制: 128 MB 提交: 404  解决: 81 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 市政府"惠民工程&q ...

  6. 中南大学2019研究生复试机试题

    中南大学2019研究生复试机试题 机试题共六题 1.选球问题 题目描述 输入 输出 样例输入 样例输出 解决代码 2.模拟出入栈游戏 题目描述 输入 输出 样例输入 样例输出 解决代码 3.爬楼梯游戏 ...

  7. 2013年中南大学研究生复试机试(1000~1004)

    目录: A:回文串问题 B:水仙花数 C:安全密码 D:最少钱币数 E:惠民工程 A:回文串问题 http://39.106.164.46/problem.php?id=1000 思路: 判断是否为回 ...

  8. 1028-可乐(中南大学18年研究生复试机试题)

    题目描述 猪年快乐!在这个快乐的日子里我们当然要去超市买可乐喝啦! 现在超市有n种可乐,第 i 种可乐的价格为C[i] ,体积为 2i-1 毫升,每种可乐都是无限供应的 ,现在你想买至少 L毫升的可乐 ...

  9. 华科研究生复试机试题代码堆积供以后参考

    #include "stdafx.h" #include <cstdio> #include <cstring> using namespace std;# ...

最新文章

  1. yudian温控表a1温度怎么补偿_冰箱冷藏温度多少合适 冰箱冷藏温度怎么调节 看完这篇你就有答案 冰箱...
  2. FEMS:微生物群落生态学数据挖掘的R包microeco
  3. mysql having子句_mysql having子句学习
  4. java sort算法名称_快速排序算法(Quick Sort)(java)
  5. 【 FPGA 】使用状态机设计一个ADC采样控制电路
  6. hbuilder ios 打包失败,无法导入p12证书的解决方案
  7. STM32F030 ADC1的DMA采样问题
  8. mybatis入门配置——基于xml配置
  9. SQL Server2005 使用FOR XML选项进行字符串的串联聚合
  10. 前端程序员容易忽视的一些基础知识
  11. LeetCode LCP 22. 黑白方格画
  12. Java中String转Long方式及注意事项
  13. 边框回归的损失函数_CVPR 2019:精确目标检测的不确定边界框回归
  14. 嵌入式语音识别系统之电路设计原理
  15. mitmproxy监听数据请求并处理数据
  16. 小米MiSans字体安装教程
  17. text/plain
  18. java期末心得,java期末小结
  19. python 四则运算
  20. 测试杀毒软件的一段代码![无毒无害]

热门文章

  1. 计算机一级wps操作题多分,计算机等级考试一级WPS考试题(六)
  2. 网络安全实验之《VPN》实验报告
  3. 云服务器的基本概念与优势
  4. 查询student表中所有李姓的学生的 SQL语句怎么写
  5. sql语句练习,oracle与mysql不同
  6. android 漫画切换,Android逆向之路---让我们试试另一种方法看漫画-(2)
  7. 骁龙870和麒麟985哪个好 骁龙870和麒麟985对比差距大吗
  8. 金山WPS移动端笔试-android方向
  9. PPT(WPS演示)+Python win32com办公自动化
  10. 古埃及太阳金经和亡灵黑经