• 题解报告:poj 1738 An old Stone Game(区间dp)


    Description

    There is an old stone game.At the beginning of the game the player picks n(1<=n<=50000) piles of stones in a line. The goal is to merge the stones in one pile observing the following rules: 
    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 input contains several test cases. The first line of each test case contains an integer n, denoting the number of piles. The following n integers describe the number of stones in each pile at the beginning of the game. 
    The last test case is followed by one zero. 

    Output

    For each test case output the answer on a single line.You may assume the answer will not exceed 1000000000.

    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):
     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn=50005;
     6 const int inf=0x7fffffff;//2147483647
     7 int n,m,t,ans,stone[maxn];
     8 void dfs(int k){
     9     int tmp=stone[k-1]+stone[k];
    10     ans+=tmp;t--;
    11     for(int i=k;i<t;++i)stone[i]=stone[i+1];//元素左移,表示删掉了一个元素
    12     int j=0;k--;
    13     for(j=k;stone[j-1]<tmp;--j)stone[j]=stone[j-1];//元素右移,找到第一个满足条件的j
    14     stone[j]=tmp;//将tmp插到j后面
    15     while(j>=3&&stone[j-2]<=stone[j]){//继续向前查找是否还有满足条件的情况
    16         int d=t-j;//保存当前t离操作点的距离d
    17         dfs(j-1);//合并第j-1堆和第j-2堆石子
    18         j=t-d;//设置新的操作点j
    19     }
    20 }
    21 int main(){
    22     while(~scanf("%d",&n)&&n){
    23         for(int i=1;i<=n;++i)scanf("%d",&stone[i]);
    24         t=2,ans=0;stone[0]=stone[n+1]=inf;
    25 for(int i=2;i<=n;++i){ 26 stone[t++]=stone[i]; 27 while(t>3&&stone[t-3]<=stone[t-1])dfs(t-2);//表示当前至少有3堆石子,并且满足stone[k-1]<=stone[k+1],k=t-2,就合并第t-3和第t-2堆石子 28 } 29 while(t>2)dfs(t-1);//如果剩下的堆数至少为3-1=2堆,则继续合并,直至剩下一堆石子 30 printf("%d ",ans); 31 } 32 return 0; 33 }
    
    
  • 相关阅读:
     一、cocos2dx之如何优化内存使用(高级篇)
    latex模版&&c++ STL用法&&画图网站
    HDU 3480 Division
    HDU 3045 Picnic Cows
    HDU 2993 MAX Average Problem
    HDU 3507 Print Article
    Luogu P2900 [USACO08MAR]土地征用Land Acquisition
    浅谈斜率优化
    POJ 2559 Largest Rectangle in a Histogram
    【计算几何】求半平面交的面积
  • 原文地址:https://www.cnblogs.com/acgoto/p/9642578.html
Copyright © 2020-2023  润新知