钢条切割问题
带备忘录的自顶向下法
时间复杂度:
思想:
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)
自底向上法
时间复杂度:
思想:
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)
矩阵链乘法
时间复杂度:
思想:
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)