算法导论-动态规划法

钢条切割问题

带备忘录的自顶向下法

时间复杂度: O(n^{2})

思想:

1, 将大问题分解(递归)

p[n] = p[i] + p[n-i]

2,  备忘

p[n-i]如果已经计算过就直接返回r[n-i]

# -*- coding:utf-8 -*-
# Author:DaoYang


def memoized_rod(p, n):
    '''
    :param p: 价格列表
    :param n: 钢条长度
    :return: 最大收益
    '''
    # 备忘录
    r = [-1 for i in range(n+1)]
    return memoized_rod_aux(p, r, n)


def memoized_rod_aux(p, r, n):
    '''
    :param p: 价格列表
    :param r: 最大子收益列表
    :param n: 钢条长度
    :return: 当前子问题最大收益
    '''
    if r[n]>=0:
        return r[n]
    if n == 0:
        q = 0
    else:
        q = -1
        for i in range(1, n+1):
            q = max(q, p[i] + memoized_rod_aux(p, r, n-i))
    r[n] = q
    return q


if __name__ == '__main__':
    p = [0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
    q = memoized_rod(p, 9)
    print(q)

自底向上法

时间复杂度: O(n^{2})

思想:

1, 子问题从小到大(大问题依赖小问题的解)求解

2, 第一重循环是为了从小到大得到r[],第二重循环才在划分

# -*- coding:utf-8 -*-
# Author:DaoYang


def bottom_up_cut_rod(p, n):
    r = [-1 for i in range(n+1)]
    r[0] = 0
    for j in range(1, n+1):
        q = -1
        for i in range(1, j+1):
            q = max(q, p[i] + r[j-i])
        r[j] = q
    return r[n]


def extended_bottom_up_cut_rod(p, n):
    r = [-1 for i in range(n + 1)]
    r[0] = 0
    s = [0 for i in range(n+1)]
    for j in range(1, n+1):
        q = -1
        for i in range(1, j+1):
            if q<p[i] + r[j-i]:
                s[j] = i
                q = p[i] + r[j-i]
        r[j] = q
    return r, s


def print_cut_rod_solution(p, n):
    (r, s) = extended_bottom_up_cut_rod(p, 9)
    while n > 0:
        print(s[n])
        n = n - s[n]


if __name__ == '__main__':
    p = [0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
    q = bottom_up_cut_rod(p, 4)
    print(q)

    print_cut_rod_solution(p, 9)



矩阵链乘法

时间复杂度:O(n^{3})

思想:

1, for l in range(2, n+1):

l为链接长度 l = 3的代价计算会用到l = 2计算的代价值

2,用k划分i-->j

# -*- coding:utf-8 -*-
# Author:DaoYang


infinite = 999999999
def matrix_chain_order(p):
    n = len(p) - 1
    m = [[-1 for i in range(n+1)] for i in range(n+1)]
    s = [[-1 for i in range(n+1)] for i in range(n+1)]

    for i in range(1, n+1):
        m[i][i] = 0
    for l in range(2, n+1):
        for i in range(1, n-l+2):
            j = i+l-1
            m[i][j] = infinite
            for k in range(i, j):
                q = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]
                if q<m[i][j]:
                    m[i][j] = q
                    s[i][j] = k
    return m, s


def print_optimal_parens(s, i, j):
    if i == j:
        print("A[%d]"%i, end='')
    else:
        print("(", end='')
        print_optimal_parens(s, i, s[i][j])
        print_optimal_parens(s, s[i][j]+1, j)
        print(")", end='')


if __name__ == '__main__':
    p = [30, 35, 15, 5, 10, 20, 25]
    (m, s) = matrix_chain_order(p)
    print(m)
    print_optimal_parens(s, 1, 6)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值