• Stone Game


    There is a stone game.At the beginning of the game the player picks n piles of stones in a line.

    The goal is to merge the stones in one pile observing the following rules:

    1. At each step of the game,the player can merge two adjacent piles to a new pile.
    2. The score is the number of stones in the new pile.

    You are to determine the minimum of the total score.

    For [4, 1, 1, 4], in the best solution, the total score is 18:

    1. Merge second and third piles => [4, 2, 4], score +2
    2. Merge the first two piles => [6, 4],score +6
    3. Merge the last two piles => [10], score +10
    

    Other two examples:
    [1, 1, 1, 1] return 8
    [4, 4, 5, 9] return 43

    这是一道比较典型的区间类DP题目.如果从小到大合并,则这题很难选择.一个比较好的方式是自顶向下,先考虑最后一次合并的费用.每一次合并的附加费用是合并的两堆石块的总数目,即新石堆的石块数目.

    我们可以枚举合并的位置,看哪个位置的成本最小,这个过程可以一直进行下去,直到一个石块的时候,合并成本是0.这中间因为枚举分割位,有非常多的重复区间.所以需要判断是否已经处理过. f的DP矩阵一开始初始化为-1,如果某个位置不是-1,则说明已经处理过,不必另外维护一个visited矩阵,另外,每次我们都要求区间和,也是一个重复性非常高的过程,可以提前求出.一个是直接求各个区间点的值,是二维矩阵,另外一个是先求前缀和数组,利用这个数组求区间和.显然后者空间复杂度低很多.代码如下:

    class Solution:
        # @param {int[]} A an integer array
        # @return {int} an integer
        def stoneGame(self, A):
            # memory search 
            if not A:
                return 0
            f = [[-1]*len(A) for i in xrange(len(A))]
            for i in xrange(len(A)):
                f[i][i] = 0
            cost = [0]*(len(A)+1)
            for i in xrange(1, len(A)+1):
                cost[i] = cost[i-1] + A[i-1]
            return self.search(A, f, cost, 0, len(A) - 1 )
            
        def search(self, A, f, cost, start, end):
            if f[start][end] >= 0:
                return f[start][end]
            import sys    
            f[start][end] = sys.maxint
            for k in xrange(start,end):
               left = self.search(A, f, cost, start, k)
               right = self.search(A, f, cost,  k+1, end)
               f[start][end] = min(f[start][end], left + right + cost[end+1] - cost[start])
            
            return f[start][end]

    时间复杂度为O(n^3),枚举两边和切分位置.空间复杂度为O(n^2),DP矩阵。

    这题有贪心做法,其实相当于霍夫曼编码,每次取最小的两堆做合并(包括新生成的堆)。这么做有可以用好几种思路,一种是排序,但是需要动态增加数字,堆是一种合理的做法。可以动态增删,另外也可以使用单调队列。具体见http://www.cnblogs.com/neverforget/archive/2011/10/13/ll.html 里面合并果子这一题。

  • 相关阅读:
    BZOJ 5059: 前鬼后鬼的守护 可并堆 左偏树 数学
    BZOJ 1975: [Sdoi2010]魔法猪学院 大水题 第k短路 spfa
    BZOJ 4003: [JLOI2015]城池攻占 左偏树 可并堆
    BZOJ 3091: 城市旅行 lct 期望 splay
    2018/3/27 省选模拟赛 140分
    BZOJ 2959: 长跑 lct 双联通分量 并查集 splay
    2018/3/26 省选模拟赛 60分
    快速排序
    插入排序法
    快速排序的两种方法
  • 原文地址:https://www.cnblogs.com/sherylwang/p/5608013.html
Copyright © 2020-2023  润新知