蓝桥杯第11天(动态规划)Python版

DP:解决贪心法的不足

DP基础介绍:

一维情况(数硬币问题):

只有1元硬币

有1元,5元硬币

def solve(s): # s为金额数
    dp = [int(1e12)]*(s+1) #初始化为无穷大
    dp[0] = 0
    for j in range (cnt):   # cnt种硬币
        for i in range(type[j],s+1) :  # 从新增的硬币值类型开始循环
            dp[i] = min(dp[i], dp[i - type[j]] +l)  # 状态转移方程
    print(dp[s])
cnt = 5 #    5种硬币
type = [1,5,10,25,50]  #5种面值
s = int(input())
solve(s)

二维情况(0/1背包问题)

状态转移:比较两种不同选择的最大价值

倒推查找装了哪些物品,如果装了新物品,价值会变,否则继承上一个价值

经典01背包问题
找到状态转移方程,切记对于dp数组,价值数组,体积数组给他大空间初始化,下标从1开始,重点在于状态转移方程
def solve(N,C):  # 从左到右,从上到下 (先种类,再体积)
    for i in range(1,N+1): # N种物品,先1种,再2种......
        for j in range(0,C+1):  # 当前背包体积
            if c[i]>j : dp[i][j] = dp[i-1][j]
            else: dp[i][j] = max(dp[i-1][j-c[i]]+w[i],dp[i-1][j])  # 装或者不装,找最大值
            
    return dp[N][C]
N,C= map(int,input().split())
n=3000
dp = [[0]*n for i in range(n)]  # 初始化dp数组,预留更大空间
c=[0]*n  # 记录体积
w=[0]*n # 记录价值
for i in range(1,N+1):   #读入N种物品的价值和体积
    c[i],w[i] = map(int,input().split())
print(solve(N,C))
01背包问题优化,优化空间大小,只是用两行队列存储

区别对比

def solve(N,C):  # 从左到右,从上到下 (先种类,再体积)
    old = 1
    new = 0
    for i in range(1,N+1): # N种物品,先1种,再2种......
        new,old = old,new  # 交换两行
        for j in range(0,C+1):  # 当前背包体积
            if c[i]>j : dp[new][j] = dp[old][j]
            else: dp[new][j] = max(dp[old][j-c[i]]+w[i],dp[old][j])  # 装或者不装,找最大值
            
    return dp[N][C]
N,C= map(int,input().split())
n=3000
dp = [[0]*n for i in range(2)]  # 初始化dp数组,预留更大空间
c=[0]*n  # 记录体积
w=[0]*n # 记录价值
for i in range(1,N+1):   #读入N种物品的价值和体积
    c[i],w[i] = map(int,input().split())
print(solve(N,C))

01背包问题再优化,只有1行存储
def solve(N,C):  # 从左到右,从上到下 (先种类,再体积)
    for i in range(1,N+1): # N种物品,先1种,再2种......
        for j in range(C,c[i]-1,-1):  # 当前背包体积,倒序进行,到c[i]-1,因为范围[c[i],C]
           dp[j] = max(dp[j],dp[j-c[i]]+w[i]) # 选或者不选           
    return dp[C]


N,C= map(int,input().split())
n=3000
dp = [0]*n  # 初始化dp数组,预留更大空间 一维
c=[0]*n  # 记录体积
w=[0]*n # 记录价值
for i in range(1,N+1):   #读入N种物品的价值和体积,从1开始计数
    c[i],w[i] = map(int,input().split())
print(solve(N,C))
01背包简化版
价值相同,最大化体积

一维dp

def solve(N,C):  # 从左到右,从上到下 (先种类,再体积)
    for i in range(1,N+1): # N种物品,先1种,再2种......
        for j in range(C,c[i]-1,-1):  # 当前背包体积,倒序进行,到c[i]-1,因为范围[c[i],C]
           dp[j] = max(dp[j],dp[j-c[i]]+c[i]) # 选或者不选           
    return dp[C]


V = int(input()) # 体积
N = int(input()) # 物品种类
n=21000
dp = [0]*n  # 初始化dp数组,预留更大空间 一维
c=[0]*n  # 记录体积

for i in range(1,N+1):   #读入N种物品的价值和体积,从1开始计数
    c[i]=int(input())
print(V-solve(N,V))

二维dp

def solve(N,C):  # 从左到右,从上到下 (先种类,再体积)
    new = 0
    old = 1
    for i in range(1,N+1): # N种物品,先1种,再2种......
        new,old = old,new
        for j in range(0,C+1):
            if c[i]>j: dp[new][j] = dp[old][j]
            else: dp[new][j] = max(dp[old][j-c[i]]+c[i],dp[old][j])      
    return dp[N][C]


V = int(input()) # 体积
N = int(input()) # 物品种类
n=21000
dp = [[0]*n for i in range(2)]  # 初始化dp数组,预留更大空间 一维
c=[0]*n  # 记录体积

for i in range(1,N+1):   #读入N种物品的价值和体积,从1开始计数
    c[i]=int(input())
print(V-solve(N,V))

完全背包问题(装的个数不受限制)

def solve(N,C):  # 从左到右,从上到下 (先种类,再体积)
    new = 0
    old = 1
    for i in range(1,N+1): # N种物品,先1种,再2种......
        new,old = old,new
        for j in range(0,C+1):
            # 先欠着(有问题)
            for k in range(0,j//c[i]+1):
                dp[new][j] = max(dp[old][j],dp[old][j-k*c[i]]+k*w[i])
            
    return dp[N][C]


V = int(input()) # 体积
N,C = map(int,input().split()) # 物品种类
n=21000
dp = [[0]*n for i in range(2)]  # 初始化dp数组,预留更大空间 一维
c=[0]*n  # 记录体积
w=[0]*n
for i in range(1,N+1):   #读入N种物品的价值和体积,从1开始计数
    c[i],w[i]=map(int,input().split())
print(solve(N,C))
最长公共子序列,线性DP

n,m = map(int,input().split())  # B n个元素 A m个元素
a = [0] + list(map(int,input().split()))
b = [0] + list(map(int,input().split()))
dp = [[0]*(m+1) for _ in range(2)]   # 注意这里是m,不是n
now = 0 ;old = 1
for i in range(1,n+1):
    now,old = old,now
    for j in range(1,m+1):
        dp[now][j] = max(dp[now][j-1],dp[old][j])
        if a[i]==b[j]:  # 相同的元素
            dp[now][j] = max(dp[now][j],dp[old][j-1]+1)
print(dp[now][m])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值