动态规划/递归 | HJ16 购物单

# 最优解1:动态规划
n, m = map(int,input().split())
primary, annex = {}, {}
for i in range(1,m+1):
    x, y, z = map(int, input().split())
    if z==0:#主件
        primary[i] = [x, y]
    else:#附件
        if z in annex:#第二个附件
            annex[z].append([x, y])
        else:#第一个附件
            annex[z] = [[x,y]]
m = len(primary)#主件个数转化为物品个数
dp = [[0]*(n+1) for _ in range(m+1)]
w, v= [[]], [[]]
for key in primary:
    w_temp, v_temp = [], []
    w_temp.append(primary[key][0])#1、主件
    v_temp.append(primary[key][0]*primary[key][1])
    if key in annex:#存在主件
        w_temp.append(w_temp[0]+annex[key][0][0])#2、主件+附件1
        v_temp.append(v_temp[0]+annex[key][0][0]*annex[key][0][1])
        if len(annex[key])>1:#存在两主件
            w_temp.append(w_temp[0]+annex[key][1][0])#3、主件+附件2
            v_temp.append(v_temp[0]+annex[key][1][0]*annex[key][1][1])
            w_temp.append(w_temp[0]+annex[key][0][0]+annex[key][1][0])#3、主件+附件1+附件2
            v_temp.append(v_temp[0]+annex[key][0][0]*annex[key][0][1]+annex[key][1][0]*annex[key][1][1])
    w.append(w_temp)
    v.append(v_temp)
for i in range(1,m+1):
    for j in range(10,n+1,10):#物品的价格是10的整数倍
        max_i = dp[i-1][j]
        for k in range(len(w[i])):
            if j-w[i][k]>=0:
                max_i = max(max_i, dp[i-1][j-w[i][k]]+v[i][k])
        dp[i][j] = max_i
print(dp[m][n])

# 最优解2:递归
def solve(i, j):
    """
    i表示遍历到第i件物品,j表示剩余钱数
    """
    if i == n+1:
        return 0
    if dp[i][j] != 0:
        return dp[i][j]
    if v[i - 1] > j or a[i - 1] != 0:
        dp[i][j] = solve(i + 1, j)
    if j >= v[i - 1] and a[i - 1] == 0:  # 买得起索引为i-1的物品
        lst = []
        for inx in range(n):
            if a[inx] == i:
                lst.append(inx)
        if len(lst) == 0:  # 没有附件
            dp[i][j] = max(solve(i+1, j), solve(i+1, j-v[i - 1])+s[i-1])
        elif len(lst) == 1:  # 有1个附件
            dp[i][j] = max(solve(i+1, j), solve(i+1, j-v[i - 1])+s[i-1])
            if v[i-1]+v[lst[0]] <= j:
                dp[i][j] = max(dp[i][j], solve(i+1,j-v[i-1]-v[lst[0]])+s[i-1]+s[lst[0]])
        elif len(lst) == 2:  # 有2个附件
            dp[i][j] = max(solve(i+1, j), solve(i+1, j-v[i - 1])+s[i-1])
            i1, i2 = lst
            if v[i-1]+v[i1] <= j:  # 可以买主件+附件1
                dp[i][j] = max(solve(i+1, j), solve(i+1, j-v[i - 1])+s[i-1], 
                               solve(i+1, j-v[i-1]-v[i1])+s[i-1]+s[i1])
            if v[i-1]+v[i2] <= j:  # 可以买主件+附件2
                dp[i][j] = max(solve(i+1, j), solve(i+1, j-v[i - 1])+s[i-1], 
                               solve(i+1, j-v[i-1]-v[i2])+s[i-1]+s[i2])
            if v[i-1]+v[i1]+v[i2] <= j:  # 可以买主件+附件1+附件2
                dp[i][j] = max(solve(i+1, j), solve(i+1, j-v[i - 1])+s[i-1], 
                               solve(i+1, j-v[i-1]-v[i1])+s[i-1]+s[i1],
                               solve(i+1, j-v[i-1]-v[i2])+s[i-1]+s[i2],
                               solve(i+1, j-v[i-1]-v[i1]-v[i2])+s[i-1]+s[i1]+s[i2])
    return dp[i][j]

while True:
    try:
        m, n = list(map(int, input().split(" ")))
        v, s, a = [], [], []
        m //= 10
        for i in range(n):
            value, pri, attach = list(map(int, input().split()))
            v.append(value // 10)
            s.append(pri*value)
            a.append(attach)
        dp = [[0] * (m + 1) for _ in range(n + 1)]
        res = solve(1, m)
        print(res)
    except:
        break

# 我的代码:参考动态规划最优解
class Good:
    def __init__(self, id, price, weight, belong) -> None:
        self.id = id  # 商品编号
        self.price = price  # 商品价格
        self.weight = weight  # 商品满意度:价格*重要度
        self.belong = belong
        self.attach = []  # 商品附件

    def add_attach(self, good):
        self.attach.append(good)

while True:
    try:
        m, N = list(map(int, input().split(" ")))
        # 1、dp数组长度为总钱数,将商品价格与总钱数同比缩小10倍,缩小dp长度
        # 2、dp由2维减为1维度,实际只记录:遍历原2维数组时当前行的上一行
        m //= 10
        dp = [0 for _ in range(m + 1)]  # 总钱数为0,1,2...m
        goods = [None, ]
        for i in range(1, N + 1):
            p, w, b = list(map(int, input().split(" ")))
            good = Good(i, p // 10, w * p, b)  # 题目说商品价格为10的整数倍
            goods.append(good)
        for good in goods[1:]:  # 遍历商品,将所有附件添加到对应主件的attach中
            if good.belong != 0:
                goods[good.belong].add_attach(good)
        for good in goods[1:]:
            if good.belong == 0:  # 遍历主件
                for j in reversed(range(m + 1)):
                    if j >= good.price:
                        dp[j] = max(dp[j], dp[j - good.price] + good.weight)
                        # 根据主件拥有附件的个数,判断怎么买让满意度最大
                        if len(good.attach) == 0:
                            continue
                        elif len(good.attach) == 1:
                            attach1 = good.attach[0]
                            # 不买;主;主+附1
                            if j >= good.price + attach1.price:  
                                dp[j] = max(
                                    dp[j],
                                    dp[j-good.price-attach1.price] + good.weight + attach1.weight,
                                )
                        elif len(good.attach) == 2:
                            attach1 = good.attach[0]
                            attach2 = good.attach[1]
                            # 不买;主;主+附1;主+附2;主+附1+附2
                            if (j >= good.price + attach1.price):  
                                dp[j] = max(
                                    dp[j],
                                    dp[j-good.price-attach1.price] + good.weight + attach1.weight,
                                )
                            if (j >= good.price + attach2.price):  
                                dp[j] = max(
                                    dp[j],
                                    dp[j-good.price-attach2.price] + good.weight + attach2.weight,
                                )
                            if (j >= good.price + attach1.price + attach2.price):  
                                dp[j] = max(
                                    dp[j],
                                    dp[j-good.price-attach1.price-attach2.price] + good.weight + \
                                        attach1.weight + attach2.weight,
                                )
                    else:
                        break
        print(dp[m])
    except:
        break

用时:7h

华为笔试刷题 文章被收录于专栏

高质量题: 1~40:HJ16,HJ22,HJ24,HJ26,HJ27,HJ28,HJ35,HJ37,HJ39; 40~80:HJ41,HJ42,HJ43,HJ44,HJ48,HJ50,HJ52,HJ53,HJ57,HJ61,HJ63,HJ64,HJ70,HJ71,HJ74,HJ77; 80~108:HJ82,HJ85,HJ88,HJ89,HJ93,HJ95,HJ98,HJ103,HJ107

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务