首页 > 试题广场 >

【模板】完全背包

[编程题]【模板】完全背包
  • 热度指数:12297 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
你有一个背包,最多能容纳的体积是V。

现在有n种物品,每种物品有任意多个,第i种物品的体积为v_i ,价值为w_i

(1)求这个背包至多能装多大价值的物品?
(2)若背包恰好装满,求至多能装多大价值的物品?

输入描述:
第一行两个整数n和V,表示物品个数和背包体积。
接下来n行,每行两个数v_iw_i,表示第i种物品的体积和价值。




输出描述:
输出有两行,第一行输出第一问的答案,第二行输出第二问的答案,如果无解请输出0。
示例1

输入

2 6
5 10
3 1

输出

10
2
示例2

输入

3 8
3 10
9 1
10 1

输出

20
0

说明

无法恰好装满背包。
示例3

输入

6 13
13 189
17 360
19 870
14 184
6 298
16 242

输出

596
189

说明

可以装5号物品2个,达到最大价值298*2=596,若要求恰好装满,只能装1个1号物品,价值为189.
参考兑换零钱的一维数组解法,把背包容量看做零钱中的target,外层循环容量,内层循环物品python3)。
import sys

def solution(n,V,v,m):
    dp1 = [0 for _ in range(V+1)]
    dp2 = [float("-inf") for _ in range(V+1)]
    dp2[0] = 0
    for i in range(V+1):
        for j in range(n):
            if i<v[j]:break
            #if dp2[i-v[j]] != float('-inf'):# 可以省略
            dp1[i] = max(dp1[i],dp1[i-v[j]]+w[j])
            dp2[i] = max(dp2[i],dp2[i-v[j]]+w[j])
    #print(dp1)
    #print(dp2)
    
    if dp2[-1] == float("-inf"):
        dp2[-1] = 0
    
    return dp1[-1],dp2[-1]
                                     

if __name__ == "__main__":
    n,V = map(int, input().split())
    v = [0 for _ in range(n)]
    w = [0 for _ in range(n)]
    p = [0 for _ in range(n)]
    for i in range(n):
        p[i] = list(map(int,input().split()))
    p = sorted(p, key=lambda x:(x[0],x[1]))
    v,w =zip(*p)
    
    #print(v,w)
    res1,res2 = solution(n,V,v,w)
    print(res1)
    print(res2)


发表于 2022-05-09 11:00:38 回复(0)
import sys

# 空间复杂度使用二维数组
def ks(n, V, P, M):
    dp = [[float("-inf") for _ in range(V+1)] for _ in range(n+1)]
    for x in range(len(dp)):
        dp[x][0] = 0
#     for y in range(len(dp[0])):
#         dp[0][y] = 0
    for i in range(1, n+1):
        for j in range(1, V+1):
            if j >= P[i]:
                for k in range(0, j//P[i]+1):
                    dp[i][j] = max(dp[i][j], dp[i-1][j-k*P[i]]+k*M[i])
            else:
                dp[i][j] = dp[i-1][j]
    print(max(max(dp)))
    if dp[-1][-1] == float("-inf"):
        print(0)
    else:
        print(dp[-1][-1])
        
# 通过19/20,算法超时        
def ks_B(n, V, P, M):
    dp = [float("-inf") for _ in range(V+1)]
    dp[0] = 0
    for i in range(1, n+1):
        for j in range(V, -1, -1):
            for k in range(0, j//P[i]+1):
                dp[j] = max(dp[j], dp[j-k*P[i]]+k*M[i])
    print(max(dp))
    if dp[-1] != float("-inf"):
        print(dp[-1])
    else:
        print(0)
    return


# 满足要求
# 思考:容量序列遍历为何可以使用正向序列?而且序列的起点可以为P[i]?
# 完全背包问题,物品i没有数量限制;
# 当 j < P[i]时,容量不足以容纳物品 i,
#   相当于d[i][j] = d[i-1][j], 在O(n)复杂度的算法中也就是不更新内容,所以可以设置起点为P[i]

def ks_C(n, V, P, M):
    dp = [float("-inf") for _ in range(V+1)]
    dp[0] = 0
    for i in range(1, n+1):
        for j in range(P[i], V+1):
            dp[j] = max(dp[j], dp[j-P[i]]+M[i])
    print(max(dp))
    if dp[-1] != float("-inf"):
        print(dp[-1])
    else:
        print(0)
    return


line1 = [int(x) for x in sys.stdin.readline().split()]
n = line1[0]
V = line1[1]


P = [0]
M = [0]
for line in sys.stdin:
    tmp = [int(x) for x in line.split()]
    P.append(tmp[0])
    M.append(tmp[1])
ks_C(n, V, P, M)
    

发表于 2021-11-08 15:00:36 回复(0)
补一个python3,与前一个背包问题的区别在于调整了dp循环顺序,从容量1到容量n进行循环,这样后续的dp就可以用到之前用过的物品
def ans():
    n, size = map(int,input().split(" "))
    v, w = [] , []
    for _ in range(n):
        t1, t2 = map(int,input().split(" "))
        v.append(t1)
        w.append(t2)
    
    dp1 = [0] * (size+1)
    dp2 = [float("-inf")] * (size+1)
    dp2[0] = 0
    
    for i in range(n):
        for j in range(1,size+1):
            if j >= v[i]:
                dp1[j] = max(dp1[j], dp1[j-v[i]] + w[i])
                dp2[j] = max(dp2[j], dp2[j-v[i]] + w[i])
    
    print(dp1[-1])
    print(dp2[-1] if dp2[-1] != float("-inf") else 0)
ans()


发表于 2021-11-08 13:30:35 回复(0)