动态规划问题严格分四步去考虑:问题结构分析——>递推关系建立——>自底向上计算(要知道最下层即最小单位)——>最优方案追踪
1.背包问题:
蛮力枚举:递归方法。
value=[24,2,9,10,9]
volume=[10,3,4,5,4]
def knapsack(value,volume,i,c):
#从第i号商品到第4号商品,容量为c时候的最优解
if c<0:
return -10000#-10000是指返回了负无穷,让这个c小于0的时候一定不能被用上
if i>4:
return 0
x=knapsack(value,volume,i+1,c)
y=knapsack(value,volume,i+1,c-volume[i])+value[i]
return max(x,y)
a=knapsack(value,volume,0,13)
print('使用暴力求解法,当背包的最大容量为13的时候,最优解为%d'%a)
# 使用暴力求解法,当背包的最大容量为13的时候,最优解为28
2.求最大子数组问题
solution1:蛮力枚举、
解法思路:
#最大紫书组问题。蛮力枚举
x=[-1,-3,3,5,-4,3,2,-2,3,6]
def voilence(x):
shuzumax=-100000
lens=len(x)
for begin in range(0,lens):
for end in range(begin,lens):
s=0
for i in range(begin,end+1):
s+=x[i]
if s>shuzumax:
shuzumax=s
return shuzumax
a=voilence(x)
print('最大值是%d'%a)
# 最大值是16
这个解法存在的最大问题就是重复!比如起点是下标为2、终点是下标为7和起点是下标为2、终点是下标为8的计算重复率很大。在计算从2 到8的时候,是不是直接可以借用从2到7的结果呢,最后只需要在从2 到7 的结果上加上一个数字即可;根据这个思路,我们提出了优化枚举法
solution 2:优化枚举法:
x=[-1,-3,3,5,-4,3,2,-2,3,6]
def voilence(x):
shuzumax=-100000
lens=len(x)
for begin in range(0,lens):
s = [0 for _ in range(lens-1 - begin + 1)]
for ending in range(begin,lens):
i=ending-begin
if i==0:
s[0]=x[begin]
i+=1
else:
s[i]=s[i-1]+x[ending]
if max(s)>shuzumax:
shuzumax=max(s)
return shuzumax
for i in range(1000):
a=voilence(x)
print('最大值是%d'%a)
#最大值是16
通过time模块,可知优化之后所用时间减少了37.5%
import time
start = time.time()
'''
<代码块>
'''
end = time.time()
print("Running time: %s seconds"%(end - start))
solution3:分而治之策略
分而治之策略是指,将复杂问题分解成若干子问题分别求得最优解、最后获得最终的理想解。“分而治之”起名的来由是周王朝无法管辖所有的国土,便将土地分封给个个诸侯来管理,各个诸侯分给自己的士大夫、一级一级往下,最后以十户为一个治理单位,从而完成对于国家的治理,所以叫做分而治之法。
solution 4:动态规划
在算D[i]之前,只需要保证D[i+1]和X[i]的值已知
但由于单单凭借D[]数组和X[]数组我们无法记录数组最后的结果,所以引入record数组。来记录最后的结果。
record数组用于记录最优解的方案
将待求解数组依次往前走,若D[i+1]>0则rec[i]=rec[i+1]且D[i]=D[i+1]+X[i];若D[i+1]<0则rec[i]=i且D[i]=x[i]
完整代码如下:
def DP(shuzu):
lens=len(shuzu)
D=[0 for _ in range(0,lens)]
# 注意一下D表示的是什么,D[i]表示的是从下标i开始的最大子序列
rec=[0 for _ in range(0,lens)]
# 注意一下rec是记录最优解是从哪里到哪里的,
D[lens-1] = shuzu[lens-1]
rec[lens-1] = lens-1
for i in range(lens-2,-1,-1):
if D[i+1]>0:
D[i]=shuzu[i]+D[i+1]
rec[i]=rec[i+1]
else:
D[i]=shuzu[i]
rec[i]=i
summax=max(D)
summaxindex=D.index(max(D))
return '最大子序列之和为%d,下标是从%d开始到%d'%(summax,summaxindex,rec[summaxindex])
#验证如下
print(DP([1,2,3,4,5]))
#最大子序列之和为15,下标是从0开始到4
print(DP([1,2,3,4,-9]))
最大子序列之和为10,下标是从0开始到3
3.最长公共子序列问题
先注意一下子序列的定义:子序列是指,将给定序列中零个或者多个序列中去掉之后的结果
注意公共子序列一定是不唯一的。
solution 1:蛮力枚举
计算顺序确定如下:
依然是建立一个rec数组进行跟踪
4.钢条切割问题