石子合并问题(直线版)-Python

问题描述:

      在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有的石子合并成一堆的最小花费。

问题分析:

     采用动态规划思想,即区间dp,dp方程式如下:


dp[i][j] 表示第 i 到第 j 堆石子合并的最优解,sum[i][j] 表示第 i 到第 j 堆石子的总数量,所以 dp[i][j] 的最优解一定在 i 到 j 中间的两个最优解的和,然后加上本次的费用。

Python实现:

# @Time   :2018/5/21
# @Author :Yinxing

def toneMerge(tone):
    n = len(tone)
    if n<=1: return 0
    if n==2: return sum(tone)  # 长度为2时,就是这两堆石头的和

    dp = [[float('inf')]*n for _ in range(n)]  # 初始化dp
    for i in range(n): dp[i][i] = 0
    sm = [tone[0]]  # 记录 列表从0 到 n 的累加和
    for i in range(1, n): sm.append(sm[i-1]+tone[i])  # 累加求和

    for gap in range(1, n):  # i 到 j 的间隔
        for i in range(n-gap):
            j = i + gap  # 确定本次  i--j
            tmp = sm[j] - [0, sm[i-1]][i > 0]  # 获取第 i 到第 j 堆石子的总数量
            for k in range(i, j):  # 选择i 到 j 的最优解
                dp[i][j] = min(dp[i][j],  dp[i][k] + dp[k+1][j] + tmp)

    return dp[0][n-1]


if __name__ == '__main__':
    # tone = [7, 6, 5, 7, 100]  # 175
    # tone = [3, 4, 5, 6, 4, 2]  # 61
    # tone = [1, 2, 3, 4, 5]  # 33
    tone = [186, 64, 35, 32, 103]  # 852
    print(toneMerge(tone))

四边不等式优化dp,Python实现(优化后时间复杂度理论为n2):

# @Time   :2018/5/22
# @Author :Yinxing

def toneMerge(tone):
    n = len(tone)
    if n<=1: return 0
    if n==2: return sum(tone)  # 长度为2时,就是这两堆石头的和

    dp = [[float('inf')]*(n+1) for _ in range(n+1)]  # 初始化dp
    sk = [[None]*(n+1) for _ in range(n+1)]  # 初始化sk

    for i in range(n+1): dp[i][i], sk[i][i] = 0, i
    sm = [tone[0]]  # 记录 列表从0 到 n 的累加和
    for i in range(1, n): sm.append(sm[i-1]+tone[i])  # 累加求和

    for gap in range(1, n):  # i 到 j 的间隔
        for i in range(n-gap):
            j = i + gap  # 确定本次  i--j
            tmp = sm[j] - [0, sm[i-1]][i > 0]  # 获取第 i 到第 j 堆石子的总数量
            i1, j1 = sk[i][j-1], sk[i+1][j]+1  # 新的区间
            for k in range(i1, j1):  # 选择i 到 j 的最优解
                if dp[i][j] > dp[i][k] + dp[k+1][j] + tmp:
                    dp[i][j], sk[i][j] = dp[i][k] + dp[k+1][j] + tmp, k  # 更新dp, 并记录最有位置k
    return dp[0][n-1]


if __name__ == '__main__':
    # tone = [7, 6, 5, 7, 100]  # 175
    # tone = [3, 4, 5, 6, 4, 2]  # 61
    # tone = [1, 2, 3, 4, 5]  # 33
    tone = [186, 64, 35, 32, 103]  # 852
    print(toneMerge(tone))

当然还可以用GarsiaWachs算法实现,理论上时间复杂度可以达到nlogn

发现问题,请记得留言指教哦

你可能感兴趣的:(Python,算法)