题解 | 购物单

购物单

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

from enum import IntEnum
import sys
input = sys.stdin.readline

def main():
    # 读取总预算 n 和物品总数 m
    n, m = map(int, input().split())
    n //= 10  # 所有物品的价格都是10的倍数,所以可以除以 10 缩小空间

    # 由于附件和主件的顺序不定,所以先将所有物品的信息保存下来
    V = [0] * (m+1)
    VAL = [0] * (m+1)
    Q = [0] * (m+1)
    for i in range(1,m+1):
        v, w, q = map(int, input().split())
        v //= 10  # 将价格缩小,方便计算
        V[i] = v
        VAL[i] = v * w
        Q[i] = q

    # 主件作为单位,附件作为主件的属性/元素
    ### 主件items[i] = [v, val, [附件1, 附件2]]——v代表价格,val代表满意度
    items = {}
    #(1) 第一次遍历,初始化主件信息
    for i in range(1,m+1):
        if Q[i] == 0:
            items[i] = [V[i], VAL[i], []]
    #(2)第二次遍历,初始化附件信息
    for i in range(1,m+1):
        if Q[i] != 0:
            items[Q[i]][2].append((V[i], VAL[i]))

    
    # 动态规划算法解题:0/1背包问题
    dp = [0] * (n+1) # dp[j]表示预算为j时的最大满意度值
    for v_main, val_main, atts in items.values():
        for j in range(n,-1,-1):  
        # 从后向前遍历,保证每次更新都是在上一次外循环的基础上
            # 1、只买主件
            if j >= v_main:
                dp[j] = max(dp[j], dp[j-v_main] + val_main)
            # 2、买主件 + 附件1
            if len(atts) >= 1:
                v1, val1 = atts[0]
                if j >= v_main + v1:
                    dp[j] = max(dp[j], dp[j-v_main-v1] + val_main + val1)
            # 3、买主件 + 附件2  / 买主件 + 两个附件
            if len(atts) >= 2:
                v1, val1 = atts[0]
                v2, val2 = atts[1]
                if j >= v_main + v2:
                    dp[j] = max(dp[j], dp[j-v_main-v2] + val_main + val2)
                if j >= v_main + v1 + v2:
                    dp[j] = max(dp[j], dp[j-v_main-v1-v2] + val_main + val1 +val2)
    # 输出最大满意度
    print(dp[n]*10)

if __name__ == '__main__':
    main()



  • 由于每个物品的价格都是10的倍数,所以将预算与价格都整除10,简化计算,避免算力浪费
  • 首先使用列表V, VAL, Q将所有物品的信息都保存下来
  • 将主件作为算法检索的单位,将附件作为主件的一种属性(附件数<=2,那么在检索时所耗费的时间就是有限的)
  • DP动态规划算法解决0/1背包问题:将预算的增加作为大循环/外循环,将主件物品的循环作为内循环/小循环,判断要不要当前物品。注意对于每一个主件物品,还需要判断要不要附件物品(也就是当前主件物品与附件物品的组合)
  • 为了节省空间,原本两重循环需要一个二维数组保存每次的结果,现在改为一维数组dp[],为了保证结果正确,那么内循环/小循环从后向前遍历(因为循环内的操作只用到了数组dp当前元素i之前的元素值,所以可以改其后的元素值,不能改之前的)
全部评论

相关推荐

Rena1ssanc...:对的,要是面评没太烂,勤更新简历等捞就行了,腾讯可以无限复活
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-10 14:10
啊啊啊啊好幸福,妈妈是我找工作发疯前的一束光
黑皮白袜臭脚体育生:看了这篇帖子之后已经第一百次质问老妈,仍然没有得到我的老妈是老板的回答
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务