石子合并问题--动态规划,贪心

参考资料:
石子合并问题–动态规划;贪心

石子合并问题是最经典的DP问题。首先它有如下3种题型:

(1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成

分析:当然这种情况是最简单的情况,合并的是任意两堆,直接贪心即可,每次选择最小的两堆合并。本问题实际上就是哈夫曼的变形。

(2)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。

(3)问题(2)的是在石子排列是直线情况下的解法,如果把石子改为环形排列,又怎么做呢?
--------------------- 
作者:JeanCheng 
来源:CSDN 
原文:https://blog.csdn.net/gatieme/article/details/49206193 
版权声明:本文为博主原创文章,转载请附上博文链接!
  • 为什么第一问贪心算法会得到最优的解法?
    证明:石子堆看成是树的叶子,每次我们合并两个堆得到一个新的堆,然后继续和其他堆继续合并,得到一棵树。总的代价为每个叶子节点的代价乘以其到根节点的路径长度。贪心算法得到的树,叶子节点代价小的总是更长或者相等,其他算法至少有两个叶子节点(大小不同)跟贪心算法相反,根据树的结构,代价更大的叶子节点的路径更长,这样得到的树的代价肯定是更大的。

  • 第二个问题:动态规划
    下面程序中p矩阵存放的是从哪里分成两半是最优的

import numpy as np


def merge_stones(stones):
    num_stones = len(stones)

    m = np.zeros(shape=(num_stones,num_stones))
    p = np.zeros(shape=(num_stones,num_stones))

    for i in range(num_stones - 1):
        m[i][i+1] = stones[i] + stones[i+1]

    for i in range(1,num_stones-1):
        for j in range(num_stones - 1 - i):
            k = j + i + 1

            min = 10000000000000
            for l in range(j+1,k):
                temp = m[j][l] + m[l+1][k] + np.sum(stones[j:k+1])
                if min > temp:
                    min = temp
                    min_p = l

            m[j][k] = min
            p[j][k] = min_p

    return m[0][num_stones-1],p


def print_ret(stones,p,start,last,first_part=False):
    if start < last:
        print('(',end='')
        mid = int(p[start][last])
        print_ret(stones,p,start,mid,True)
        print_ret(stones,p,mid+1,last,False)
        print(')',end='')
    else:
        print(stones[start],end='')

    if first_part:
        print(',',end='')


if __name__ == '__main__':
    # while True:
    #     num_stones = int(input('Input:\n'))
    #     stones = []
    #     for s in map(int, input().split()):
    #         stones.append(s)
    #
    #     if num_stones == len(stones):
    #         merge_stones(stones)
    #     else:
    #         print('输入数量不对')

    max,p = merge_stones([4,4,5,9])
    print_ret([4,4,5,9],p,0,len([4,4,5,9])-1)
  • 第三个问题:跟上面的问题相似,只是有一个圈罢了。
    原文作者:抬头挺胸才算活着
    原文地址: https://www.jianshu.com/p/128cd7e05dd1
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞