洛谷 P1064 [NOIP2006 提高组] 金明的预算方案 python解析

P1064 [NOIP2006 提高组] 金明的预算方案

时间:2023.11.19
题目地址:[NOIP2006 提高组] 金明的预算方案

题目分析

动态规划的0-1背包,采用动态数组。如果不了解的话,可以先看看这个背包DP
这个是0-1背包的标准状态转移方程 f [ j ] = m a x ( f [ j − w [ i ] ] + v [ i ] , f [ j ] ) f[j] = max(f[j-w[i]] + v[i], f[j]) f[j]=max(f[jw[i]]+v[i],f[j])。那么就基于对这个方程进行展开。
五种情况:
① 不放。
m a x ( ) max() max()
② 放主物品,不带副品。
f [ j ] = m a x ( f [ j − m a i n _ a r t [ i ] [ 0 ] ] + m a i n _ a r t [ i ] [ 1 ] , f [ j ] ) f[j] = max(f[j-main\_art[i][0]] + main\_art[i][1], f[j]) f[j]=max(f[jmain_art[i][0]]+main_art[i][1],f[j])
③ 放主物品,带1副品。
f [ j ] = m a x ( f [ j ] , f [ j − m a i n _ a r t [ i ] [ 0 ] − r a l _ a r t [ i ] [ 1 ] [ 0 ] ] + m a i n _ a r t [ i ] [ 1 ] + r a l _ a r t [ i ] [ 1 ] [ 1 ] ) f[j] = max(f[j], f[j-main\_art[i][0]-ral\_art[i][1][0]] + main\_art[i][1] + ral\_art[i][1][1]) f[j]=max(f[j],f[jmain_art[i][0]ral_art[i][1][0]]+main_art[i][1]+ral_art[i][1][1])
④ 放主物品,带2副品。
f [ j ] = m a x ( f [ j ] , f [ j − m a i n _ a r t [ i ] [ 0 ] − r a l _ a r t [ i ] [ 2 ] [ 0 ] ] + m a i n _ a r t [ i ] [ 1 ] + r a l _ a r t [ i ] [ 2 ] [ 1 ] ) f[j] = max(f[j], f[j-main\_art[i][0]-ral\_art[i][2][0]] + main\_art[i][1] + ral\_art[i][2][1]) f[j]=max(f[j],f[jmain_art[i][0]ral_art[i][2][0]]+main_art[i][1]+ral_art[i][2][1])
⑤ 放主物品,带1、2副品。
f [ j ] = m a x ( f [ j ] , f [ j − m a i n _ a r t [ i ] [ 0 ] − r a l _ a r t [ i ] [ 1 ] [ 0 ] − r a l _ a r t [ i ] [ 2 ] [ 0 ] ] + m a i n _ a r t [ i ] [ 1 ] + r a l _ a r t [ i ] [ 1 ] [ 1 ] + r a l _ a r t [ i ] [ 2 ] [ 1 ] ) f[j] = max(f[j], f[j-main\_art[i][0]-ral\_art[i][1][0]-ral\_art[i][2][0]] + main\_art[i][1] + ral\_art[i][1][1] + ral\_art[i][2][1]) f[j]=max(f[j],f[jmain_art[i][0]ral_art[i][1][0]ral_art[i][2][0]]+main_art[i][1]+ral_art[i][1][1]+ral_art[i][2][1])
这些理解清楚了就简单了。
但是超时了三个,enmm…,有点那啥,主要是理解思路和过程,掌握方法好吧。
1

代码

n, m = map(int, input().split())
main_art = [[] for _ in range(m+1)]
ral_art = [[0, [0]*2, [0]*2] for _ in range(m+1)] 
# 例:[[0, [0, 0], [0, 0]], [1, [300, 600], [0,0]], [2, [200, 400], [100, 400]]]
for i in range(1, m+1):
    v, p, q = map(int, input().split())
    if q == 0:
        main_art[i] = [v, p*v]
    else:
        ral_art[q][0] += 1
        ral_art[q][ral_art[q][0]][0] = v
        ral_art[q][ral_art[q][0]][1] = v*p
        
f = [0]*(n+1)
for i in range(1, m+1):
    if not main_art[i]:
        continue
    for j in range(n, main_art[i][0]-1, -1):
        f[j] = max(f[j-main_art[i][0]] + main_art[i][1], f[j])
        if j >= main_art[i][0] + ral_art[i][1][0]: # 判断剩余钱(空间)能否买(放)这个物品。
            f[j] = max(f[j], f[j-main_art[i][0]-ral_art[i][1][0]] + main_art[i][1] + ral_art[i][1][1])
        if j >= main_art[i][0] + ral_art[i][2][0]: # 判断剩余钱(空间)能否买(放)这个物品。
            f[j] = max(f[j], f[j-main_art[i][0]-ral_art[i][2][0]] + main_art[i][1] + ral_art[i][2][1])
        if j >= main_art[i][0] + ral_art[i][1][0] + ral_art[i][2][0]: # 判断剩余钱(空间)能否买(放)这个物品。
            f[j] = max(f[j], f[j-main_art[i][0]-ral_art[i][1][0]-ral_art[i][2][0]] + main_art[i][1] + ral_art[i][1][1] + ral_art[i][2][1])
print(f[n])
  • 10
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值