题解报告:poj 1738 An old Stone Game(区间dp)
Description
At each step of the game,the player can merge two adjoining piles to a new pile.The score is the number of stones in the new pile.
You are to write a program to determine the minimum of the total score.
Input
The last test case is followed by one zero.
Output
Sample Input
1
100
3
3 4 3
4
1 1 1 1
0
Sample Output
0
17
8
解题思路:GarsiaWachs算法,时间复杂度为O(n^2)。它的算法步骤如下:设序列是stone[1~n],从左往右找一个满足stone[k-1]<=stone[k+1]的k,然后合并stone[k-1]和stone[k]为tmp,再从位置k-1向左找一个最大的j,使其满足stone[j]>tmp,并将tmp插到j的后面。一直重复,直到将所有石子合并。在这个过程中,可以假设stone[0]和stone[n+1]是+∞的。
举个例子:186 64 35 32 103
∵35<103,∴第一次满足条件的k下标(下标从0开始计算)为3,我们先把35和32删除,得到它们的和67,并向前寻找一个第一个大于67的数,把67插入到它后面,得到:186 67 64 103,现在由5个数变为4个数了,继续同样的操作: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)。
(转)补证:问题分析:(1)、假设我们只对3堆石子a,b,c进行比较, 先合并哪2堆, 使得代价总和最小。
score1=(a+b)+((a+b)+c),score2=(b+c)+((b+c)+a),当score1<=score2时,化简得a<=c,因此可得出只要a和c的关系确定,合并的顺序也就确定了。
(2)、GarsiaWachs算法, 就是基于(1)的结论实现的。找出序列中满足stone[k-1]<=stone[k+1]最小的k, 合并stone[k-1]+stone[k]为tmp, 接着往前面找满足条件stone[j]>tmp, 把tmp值插入stone[j]的后面(数组的右边). 循环这个过程一直到只剩下一堆石子结束。
(3)、为什么要将tmp插入stone[j]后面, 可以理解为(1)的情况,从stone[j+1]到stone[k-2]看成一个整体stone[mid],那么对于stone[j],stone[mid], tmp,必有tmp<stone[j],∴不管怎样都是stone[mid]和tmp先合并, 即将tmp值插入stone[j]的后面是不影响结果的。
AC代码(141ms):
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=;
const int inf=0x7fffffff;//2147483647
int n,m,t,ans,stone[maxn];
void dfs(int k){
int tmp=stone[k-]+stone[k];
ans+=tmp;t--;
for(int i=k;i<t;++i)stone[i]=stone[i+];//元素左移,表示删掉了一个元素
int j=;k--;
for(j=k;stone[j-]<tmp;--j)stone[j]=stone[j-];//元素右移,找到第一个满足条件的j
stone[j]=tmp;//将tmp插到j后面
while(j>=3&&stone[j-]<=stone[j]){//继续向前查找是否还有满足条件的情况
int d=t-j;//保存当前t离操作点的距离d
dfs(j-);//合并第j-1堆和第j-2堆石子
j=t-d;//设置新的操作点j
}
}
int main(){
while(~scanf("%d",&n)&&n){
for(int i=;i<=n;++i)scanf("%d",&stone[i]);
t=,ans=;stone[]=stone[n+]=inf;
for(int i=;i<=n;++i){
stone[t++]=stone[i];
while(t>&&stone[t-]<=stone[t-])dfs(t-);//表示当前至少有3堆石子,并且满足stone[k-1]<=stone[k+1],k=t-2,就合并第t-3和第t-2堆石子
}
while(t>)dfs(t-);//如果剩下的堆数至少为3-1=2堆,则继续合并,直至剩下一堆石子
printf("%d\n",ans);
}
return ;
}
题解报告:poj 1738 An old Stone Game(区间dp)的更多相关文章
- POJ 1651:Multiplication Puzzle(区间DP)
http://poj.org/problem?id=1651 题意:给出n个数字,每取中间一个数,就会使得权值加上中间这个数和两边的乘积,求取剩两个数最少的权值是多少. 思路:区间dp. 一开始想了挺 ...
- [08山东省选]2298 石子合并 即POJ 1738 An old Stone Game
2298 石子合并 2008年省队选拔赛山东 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 在 ...
- POJ 1738 An old Stone Game(石子合并 经典)
An old Stone Game Time Limit: 5000MS Memory Limit: 30000K Total Submissions: 3672 Accepted: 1035 ...
- 【题解】POJ 3417 Network(倍增求LCA+DP+树上差分)
POJ3417:http://poj.org/problem?id=3417 思路 我们注意到由“主要边”构成一颗树 “附加边”则是非树边 把一条附加边(x,y)加入树中 会与树上x,y之间构成一个环 ...
- poj 1694 An Old Stone Game 树形dp
//poj 1694 //sep9 #include <iostream> #include <algorithm> using namespace std; const in ...
- POJ 2671 Jimmy's Bad Day题解(很详细很友好,类似区间dp)
有问题的话欢迎在评论区提出 题意: 题目链接 你是一个送快递的,现在给你一个环,环的边有权值,代表走这条边所花的时间,每个点代表一个地点,点有点权,代表这个点上有多少货物需要你送.初始时间\(t=0\ ...
- 题解报告:hdu 1520 Anniversary party(树形dp入门)
Problem Description There is going to be a party to celebrate the 80-th Anniversary of the Ural Stat ...
- POJ 题目1141 Brackets Sequence(区间DP记录路径)
Brackets Sequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 27793 Accepted: 788 ...
- POJ 题目3280 Cheapest Palindrome(区间DP)
Cheapest Palindrome Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7148 Accepted: 34 ...
随机推荐
- BootStrap-DualListBox怎样改造成为双树
BootStrap-DualListBox能够实现将所选择的列表项显示到右边,未选的列表项显示到左边. 但是左右两边的下拉框中都是单级列表.如果要实现将两边都是树(缩进树),选择某个节点时,其子节点也 ...
- xamarin.android Activity之间跳转与传值
前言 由于需要,所以接触到这个新的安卓开发模式,我会把我的学习经历全都记录下来,希望对大家有用. 导读 关于Activity,学习过安卓的人也应该明白什么是Activity,推荐新手去看YZF的这篇文 ...
- MYSQL进阶学习笔记十二:MySQL 表分区!(视频序号:进阶_29,30)
知识点十三:MySQL 表的分区(29) 一.什么要采用分区: 分区的定义: 当数据量过大的时候(通常是指百万级或千万级数据的时候),这时候需要将一张表划分几张表存储.一些查询可以得到极大的优化,这主 ...
- Silverlight 2中实现文件上传和电子邮件发送
Silverlight 2中实现文件上传和电子邮件发送 [收藏此页] [打印] 作者:IT168 TerryLee 2008-05-30 内容导航: 使用Web Service上传文件 [I ...
- 一步一步学Silverlight 2系列(32):图形图像综合实例—“功夫之王”剧照播放
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 创建app前的环境配置/AppIcon/启动图片
1.真机调试http://blog.csdn.net/tht2009/article/details/48580569 2.创建app前的环境配置
- Java 网络处理(net io URL 等)
1. URL 类 URL 类的两个重要方法: openStream():打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream. URL url = new URL(" ...
- QTextEdit/QPlainTextEdit添加文字超出视图后,滚动条自动移至最底部
void ThreadExit::onTaskPerformState(const QString& strStatus) { //追加文本(ui.taskStatusTextEdit是一个Q ...
- AutoIt:获取计算机已安装程序列表
$file = FileOpen(@ScriptDir&"\RegInstalledItems.csv",1) if $file = -1 Then ConsoleWrit ...
- Python项目使用memcached缓存
前言许多Web应用都将数据保存到MySQL这样的关系型数据库管理系统中,应用服务器从中读取数据并在浏览器中显示. 但随着数据量的增大.访问的集中,就会出现数据库的负担加重.数据库响应恶化. 网站显示延 ...