Python 动态规划算法

时间:2022-11-12 22:55:01

背包问题

假设你是一个小偷,背一个可装4磅东西的背包。可盗窃的商品有如下3件:

  1. 音响,4磅,价值3000美元
  2. 笔记本电脑,3磅,价值2000美元
  3. 吉他,1磅,价值1500美元
    为了让盗窃的商品价值最高,你该选择哪些商品?

思路:

《算法图解》第9章动态规划

代码:

w=[0,4,3,1].  #商品的重量列表,w[0]占位用
p=[0,3000,2000,1500] #价值列表,p[0]无用
n=len(w)-1 #计算物体的个数
m=4 #背包的最大载重量
optp=[[0 for col in range(m+1)] for raw in range(n+1)]
#optp 相当于创建了一个n*m的全零矩阵,n行为物件,m列为子背包载重量。
def solution(w,p,m):
n=len(w)-1
for i in range(1,n+1):
for j in range(1,m+1):
if j>=w[i]:
optp[i][j]=max(optp[i-1][j],p[i]+optp[i-1][j-w[i]]
else:
optp[i][j]=optp[i-1][j]
#下面这段代码是为了求出盗窃的商品价值最高时的商品组合x。
j=m
x=[]
for i in range(n,0,-1):
if optp[i][j]>optp[i-1][j]:
x.append(i)
j=j-w[i]
return optp[n][m],x

cpu双核问题

网易笔试:一种CPU的两个核能够同时处理任务,现在有n个已知数据量的任务需要交给cpu处理,假设已知CPU的每个核1秒可以处理1kb,每个核同时只能处理一项任务。n个任务可以按照任意顺序放入cpu进行处理,现在需要设计一个方案让CPU处理完这批任务所需时间最少,求这个最小时间。
输入包括2行:
第一行为整数n(1<=n<=50)
第二行为n个整数lengthi单位时b,每个数均为1024的倍数。
输出一个整数,表示最少需要处理的时间。

思路

问题实质是动态规划问题,把数组分成2部分,使得2部分的和相差最小。差值最小就是说2部分的和最接近,而且各部分的和与总和的一半也是最接近。假设用sum1表示第一部分的和,sum2表示第二部分的和,sum表示所有数的和,那么sum1+sum2=sum。假设sum1<sum2,那么sum/2-sum1=sum2-sum/2.所以我们就有目标了,使得sum1<=sum/2的条件下尽可能大。也就是说从n个数中选出某些数,使得这些数尽可能的接近或等于sum1.
抽象为背包问题:
背包的最大载重量(即一个核运行的最长时间):sum//2+1
商品的价值与重量相等,都为length[i]
问题就变成在一个核运行的最长时间内运行价值最大的任务数。

代码

w=[0,3072,3072,7168,3072,1024] #重量
w=list(map(lambda x:x//1024,w)) #转化成kb
p=w #价值
n=sum(w)//2+1
optp=[[0 for j in range(n+1)] for i in range(len(w))]
for i in range(1,len(p)):
for j in range(1,n+1):
if j >= p[i]:
optp[i][j]=max(optp[i-1][j],p[i]+optp[i-1][j-w[i])
else:
optp[i][j]=optp[i-1][j]
return optp[-1][-1]

LIS问题

最长上升子序列

代码

lis=[2,1,5,3,6,4,8,9,7]
d=[1]*len(lis)
res=1
for i in range(len(lis)):
for j in range(i):
if lis[j]<=lis[i] and d[i]<d[j]+1:
d[i]=d[j]+1
if d[j]>res:
res=d[j]
return res

LCS问题

最长公共子序列

代码

s1=[1,3,4,5,6,7,7,8]
s2=[3,5,7,4,8,6,7,8,2]
d=[[0]*(len(s2)+1) for i in range(len(s1)+1)]
for i in range(1,len(s1)+1):
for j in range(1,len(s2)+1):
if s1[i-1]==s2[j-1]:
d[i][j]=d[i-1][j-1]+1
else:
d[i][j]=max(d[i-1][j],d[i][j-1])
return d[-1][-1]

最长公共子串问题

代码

s1=[1,3,4,5,6,7,7,8]
s2=[3,5,7,4,8,6,7,8,2]
d=[[0]*(len(s2)+1) for i in range(len(s1)+1)]
res=0
for i in range(1,len(s1)+1):
for j in range(1,len(s2)+1):
if s1[i-1]==s2[j-1]:
d[i][j]=d[i-1][j-1]+1
res=max(d[i][j],res)
else:
d[i][j]=0
return res