Python算法--动态规划--0-1背包变化题

题目

输入的第 1 行,为两个正整数N,m,用一个空格隔开:

(其中 N ( N<32000 )表示总钱数, m (m <60 )为可购买的物品的个数。)

从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q

(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)

答案与解析

n,m = map(int,input().split())
mainThing = {}
attach = {}
for i in range(1,m+1):
    v,p,q = map(int,input().split())
    if q==0:# 存储主件
        mainThing[i] = [v,p]
    else: # 存储附件
        if q in attach:# 存储第2个附件
            attach[q].append([v,p])
        else:# 存储第1个附件
             attach[q] = [[v,p]]
"""
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i])

dp[i]只依赖dp[i-1],状态转移方程就可以改为:
dp[j] = max(dp_pre[j], dp_pre[j-w[i]]+v[i])

dp_pre[j]存储上一次得到的值,现在只需要2*n的空间就能得到结果。
继续观察可以发现,其实只用一个一维dp数组就行,不需要额外的辅助数组。
让j从n到1遍历,此时每次更新的dp[j]时,max函数中dp[j]和 dp[j-w[i]]都是上次保存的值。

状态转移方程变为:
for j in [n...1]:
dp[j] = max(dp[j], dp[j-w[i]]+v[i])

如果从1到n遍历的话dp[j-w[i]]不能保证还是上次的值,
这也进一步说明为什么用一维数组时需要从n到1遍历。
"""
dp = [0]*(n+1)
for k in mainThing:
    w,val = [],[]
    w.append(mainThing[k][0])#1、主件
    val.append(mainThing[k][0]*mainThing[k][1])
    if k in attach:# 存在附件
        w.append(w[0]+attach[k][0][0])#2、主件+附件1
        val.append(val[0]+attach[k][0][0]*attach[k][0][1])
        if len(attach[k])>1:#存在两附件
            w.append( w[0]+attach[k][1][0])#3、主件+附件2
            val.append(val[0]+attach[k][1][0]*attach[k][1][1])
            w.append( w[0]+attach[k][0][0]+attach[k][1][0])#4、主件+附件2+附件1
            val.append(val[0]+attach[k][0][0]*attach[k][0][1]+attach[k][1][0]*attach[k][1][1])
    for j in range(n,-1,-10):
        for k in range(len(w)):
            if j-w[k]>=0:
                dp[j] = max(dp[j], dp[j-w[k]]+val[k])
print(dp[n])

            
        
        
    
       

你可能感兴趣的:(python)