题解报告: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 ...
随机推荐
- Android Camera系统深入理解
1. Android Camera系统架构 http://blog.csdn.net/myarrow/article/details/8489674
- ARC机制之__strong具体解释
ARC机制之__strong具体解释 __strong 解析: 默认情况下,一个指针都会使用 __strong 属性,表明这是一个强引用.这意味着,仅仅要引用存在,对象就不能被销毁.这是一种所期望的 ...
- debian iptables持久化
1 保存iptables iptables-save > /etc/iptables.rules 2 创建启动文件 touch /etc/network/if-pre-up.d/iptabl ...
- top load average
负载均值 等待运行的进程数
- C语言文件读写Demo
CIODemo.c #include <stdio.h> #include <time.h> #define INPUT_BUFFER_SIZE 100 * 1024 int ...
- 【POJ 1159】Palindrome
[POJ 1159]Palindrome 近期各种题各种奇葩思路已经司空见惯了...又新出个滚动数组= = 该题另一点须要知道 最少须要补充的字母数 = 原序列S的长度 - S和S'的最长公共子串长度 ...
- uCOS-II模拟(VS2010&WIN32)
转自http://www.amobbs.com/thread-5462878-1-1.html 自学uCOS-II源码,在论坛上上看到大神在WIN7 Visual Studio 2010环境下调试uC ...
- SQL Server 数据库备份策略,第一周运行失败的原因
一般生产库,采用 每10分钟备份Log,每天备份Diff,每周备份Full的策略. 同时存在异地备份.异地备份可使用SQL Server本身的cmdshell存储过程,调用系统命令. 在为新数据库,建 ...
- linux初级学习笔记二:linux操作系统及常用命令,文件的创建与删除和命名规则,命令行展开以及linux中部分目录的作用!(视频序号:02_3)
本节学习的命令:tree,mkdir,rmdir,touch,stat,rm 本节学习的技能:Linux中主要的目录作用以及特殊的目录文件: 文件的命名规则,命令行展开: 文件的创建与删除: Linu ...
- codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)
题目链接: C. Mashmokh and Reverse Operation time limit per test 4 seconds memory limit per test 512 mega ...