美文网首页
背包问题

背包问题

作者: madao756 | 来源:发表于2020-03-16 12:35 被阅读0次

前言: 总结模板

0X00 模板总结

首先背包问题对于「状态」有一个通用的表示方法: dp[i][j]

代表使用前 i 个物体在不超过体积 j 的情况下的获得的最大价值

理所应当可以根据第 i 个物品计算状态

0 1 背包问题

01背包问题

根据第 i 个物品使不使用可以写出「状态转移方程」:

dp[i][j] = max(dp[i-1][j], dp[i-1][j-v]+w)

意思就是使用该物品和不使用该物品取一个最大值

写出 0 1 背包的通用解法:

n, cap = map(int, input().split())
mat = [[0] * 2 for _ in range(n+1)]
for x in range(1, n+1):
    mat[x][:] = map(int, input().split())
    
dp = [[0] * (cap + 1) for _ in range(n+1)]

for x in range(1, n+1):
    v, w = mat[x]
    for y in range(cap+1):
        dp[x][y] = dp[x-1][y]
        if y < v: continue
        dp[x][y] = max(dp[x][y], dp[x-1][y-v]+w)
        
print(dp[n][cap])

优化成 1 维 dp

n, cap = map(int, input().split())
mat = [[0] * 2 for _ in range(n+1)]
for x in range(1, n+1):
    mat[x][:] = map(int, input().split())
    
dp = [0] * (cap + 1)

for x in range(1, n+1):
    v, w = mat[x]
    for y in range(cap, v-1, -1):
        dp[y] = max(dp[y], dp[y-v]+w)
        
print(dp[cap])

完全背包问题

完全背包问题

「完全背包」问题就是在 01 背包问题上加上了物品个数不限, 划分从选不选变成了选几个

n, cap = map(int, input().split())
mat = [[0] * 2 for i in range(n+1)]

for x in range(1, n+1):
    mat[x][:] = map(int, input().split())
    
dp = [[0] * (cap+1) for _ in range(n+1)]

for x in range(1, n+1):
    for y in range(cap+1):
        k, v, w = 0, mat[x][0], mat[x][1]
        while k * v <= y:
            dp[x][y] = max(dp[x][y], dp[x-1][y - k*v] + k*w)
            k += 1
            
print(dp[n][cap])

优化成 O(n^2):

已知:

dp[x][y] = max(dp[x-1][y], dp[x-1][y-v] + w, dp[x-1][y-2*v]+2*w+...+dp[x-1][y-k*v]+k*w)  y > k*v

dp[x][y-v] = max(dp[x-1][y-v], dp[x-1][y-2*v] + w, ..., dp[x-1][y-k*v]+k*w) y > k*v

所以

dp[x][y] = max(dp[x-1][y], dp[x][y-v]+w)
n, cap = map(int, input().split())
mat = [[0] * 2 for i in range(n+1)]

for x in range(1, n+1):
    mat[x][:] = map(int, input().split())
    
dp = [[0] * (cap+1) for _ in range(n+1)]

for x in range(1, n+1):
    v, w = mat[x][0], mat[x][1]
    for y in range(cap+1):
        dp[x][y] = dp[x-1][y]
        if y < v: continue
        dp[x][y] = max(dp[x][y], dp[x][y - v] + w)
            
print(dp[n][cap])

优化成一维 dp:

直接去掉一维, 由于是从当前层来的, 所以顺序是从小到大

n, cap = map(int, input().split())
mat = [[0] * 2 for i in range(n+1)]

for x in range(1, n+1):
    mat[x][:] = map(int, input().split())
    
dp = [0] * (cap+1)

for x in range(1, n+1):
    v, w = mat[x][0], mat[x][1]
    for y in range(v, cap+1):
        dp[y] = max(dp[y], dp[y - v] + w)
            
print(dp[cap])

多重背包问题

多重背包问题

「多重背包」问题就是在 01 背包问题上加上了物品个数有限, 划分从选不选变成了选几个

n, cap = map(int, input().split())
mat = [[0] * 3 for _ in range(n+1)]
for x in range(1, n+1):
    mat[x][:] = map(int, input().split())

dp = [[0] * (cap+1) for _ in range(n+1)]

for x in range(1, n+1):
    for y in range(cap+1):
        v, w, num = mat[x]
        for k in range(num+1):
            if k * v > y: break
            dp[x][y] = max(dp[x][y], dp[x-1][y - k*v]+k*w)

print(dp[n][cap])

优化从 O(n*cap*s)O(n*cap*logs ) 其中:

  • s 是最多物品个数

基本原理如下:

0 ~ 200

可以被

1, 2, 4, 8, 16, 32, 64, 73

表示

所以任意一个物品的个数可以拆分, 比如有个物品的个数是 200 就可以由 代表着 1, 2, 4, 8, 16, 32, 64, 73 的 8 个新物品表示

最后使用 01 背包解决

n, cap = map(int, input().split())
mat = [[0, 0] for _ in range(15000)]
cnt = 1
for _ in range(1, n+1):
    v, w, s = map(int, input().split())
    k = 1
    while k <= s:
        mat[cnt][0], mat[cnt][1] = k*v, k*w
        cnt += 1
        s -= k
        k *= 2
    if s > 0:
        mat[cnt][0], mat[cnt][1] = s*v, s*w     
        cnt += 1

# 01 背包解决这个问题
n = cnt - 1
dp = [0] * (cap+1)

for x in range(n+1):
    v, w = mat[x]
    for y in range(cap, v-1, -1):
        dp[y] = max(dp[y], dp[y-v] + w)

print(dp[cap])

分组背包问题

分组背包问题的状态表示方程的含义就有点变化了

dp[i][j] 表示使用 前 i 组物品, 在不超过 j 体积的情况下的最大价值

n, cap = map(int, input().split())

mat = [[]for _ in range(n+1)]

for x in range(1, n+1):
    m = int(input())
    for y in range(m):
        temp = list(map(int, input().split()))
        mat[x].append(temp)

dp = [[0] * (cap+1) for _ in range(n+1)]

for x in range(1, n+1):
    for y in range(cap+1):
        # 不使用 x 组
        dp[x][y] = dp[x-1][y]
        # 使用 x 组
        for k in range(len(mat[x])):
            v, w = mat[x][k]
            # 使用 1 次
            if y < v: continue
            dp[x][y] = max(dp[x][y], dp[x-1][y - v] + w)

print(dp[n][cap])

相关文章

  • 背包问题(完全背包)

    动态规划合集: 1.矩阵链乘法2.投资组合问题3.完全背包问题4.01背包问题5.最长公共子序列 例题3——背包问...

  • Algorithm进阶计划 -- 动态规划(下)

    经典动态规划背包问题最长子序列问题 1. 背包问题 1.1 0-1 背包问题 0-1 背包问题,描述如下: 上面...

  • 背包问题

    0-1背包问题 问题 n个物体,它们各自有重量和价值,给定一个有容量的背包,如何让背包里装入的物体价值总和最大? ...

  • 背包问题

    问题描述 假如有一个能装下4磅的背包,如何从下列商品列表中选择商品填充背包,使价值达到最大: 动态规划 要解决背包...

  • 背包问题

    (1)0-1背包容量为10的背包,有5种物品,每种物品只有一个,其重量分别为5,4,3,2,1,其价值分别为1,2...

  • 背包问题

  • 背包问题

    01背包(物品只有一个) 有N件物品和一个容量为V的背包。第i建物品的费用是w[i],价值是v[i]。求解将哪些物...

  • 背包问题

    1. 01背包 状态说明:背包体积为v,物品个数为n,f[n,v]表示前n件物品加入背包的最大价值。c_i,w_i...

  • 背包问题

    01背包 优化空间复杂度,变为一维; 外循环依然是n从1->N, 注意内循环 v是从V->0,为什么内循环是V->...

  • 背包问题

    介绍 学习动态规划算法的经典例题。动态规划算法一般有3个特征1、最优化原理:最优解所包含的子问题的解也是最优的。2...

网友评论

      本文标题:背包问题

      本文链接:https://www.haomeiwen.com/subject/vphgehtx.html