动态规划经典题型
动态规划题
二进制数中1的个数
//0到num数中每个二进制表示中1的个数
def countBits(self, num):
dp = [0]*(num+1)
for i in range(0, num+1):
dp[i] = (i & 1) + dp[i>>1]//位运算
return dp
扩展问题:
- 给定两个正整数A,B,快速找出二进制表示中不同位数的个数?//AB异或,再求该数的1的个数
- 判断一个数是否时2的幂//n&(n-1)==0;
- v&=(v-1) ;cnt++;求1 的个数
硬币兑换方法数
def countMethod(arr,num):
arr.sort()
dp = [0]*(num+1)
dp[0] =1
for i in range(len(arr)):
for j in range(arr[i],num+1):
dp[j] = (dp[j]+dp[j-arr[i]])%1000000007
//每个循环新增一类硬币,方法数新增(当前值减去硬币值后的方法数)
return dp[-1]
arr = [1,5,10,25]
print(countMethod(arr,20))
硬币兑换最少硬币数
def Mincoin(arr,num):
arr.sort()
dp = [0]*(num+1)
newcoins = {}//记录每次新增的硬币,用于回溯硬币组合
for i in range(1,num+1):
coin=i
newcoin=0//新增硬币类型,也做是否能拼凑的标记
for j in [c for c in arr if c<=i]:
if dp[i-j]+1<coin and dp[i-j]!=-1:
coin = dp[i-j]+1
newcoin=j
if newcoin!=0://可组合
dp[i]=coin
else://不能组合
dp[i]=-1
newcoins[i]=newcoin
return dp[-1],newcoins
arr = [2,3]
num = 11
res,newcoins = Mincoin(arr,num)
coin = num
if newcoins[num]!=0:
while coin>0:
thisCoin = newcoins[coin]
print(thisCoin)
coin = coin-thisCoin
print(res)
0-1背包
def back01():
C = 10 # 背包总体积
num = 5 # 个数
v = [4, 3, 5, 2, 5] # 体积
price = [9, 6, 1, 4, 1] # 价格
dp=[0 for i in range(C+1)] #
for i in range(num): #
for j in range(C,v[i]-1,-1): # 逆序,保证每种类型只有一个
dp[j]=max(dp[j],dp[j-v[i]]+price[i])
print("一维递归计算结果:",dp[C])
back01()
完全背包
def backFull():
C = 10 # 背包总体积
num = 5 # 个数
v = [4, 3, 5, 2, 5] # 体积
price = [9, 6, 1, 4, 1] # 价格
dp=[0 for i in range(C+1)] #
for i in range(num): #
for j in range(v[i],C+1): # 新增物品,比较价格
dp[j]=max(dp[j],dp[j-v[i]]+price[i])
print("一维递归计算结果:",dp[C])
backFull()
高楼扔鸡蛋问题
import sys
def eggDrop(k,n):
visited={}
def dp(k,n):
if k==1:
return n
if n==0:
return 0
if (k,n) in visited:
return visited[(k,n)]
res = sys.maxsize
for i in range(1,n+1):
res = min(res,max(dp(k,n-i),dp(k-1,i-1))+1)
visited[(k,n)] = res
return res
return dp(k,n)
res = eggDrop(2,100)
print(res)