牛客网 购物单--王强今天很开心 python 动态规划

购物单-动态规划

  • 1.题目
  • 2.python实现代码
  • 3.编程思路
  • 4.参考文献

1.题目

王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。

2.python实现代码

def order_tune(a,min_m):
    j=0
    #调整列表顺序,将附件放到对应主件的后面
    for item in a:
        if item[2]!=0:
            a[item[2]-1].extend(item)
        else:
            if item[0]<min_m:
                min_m=item[0]
            j+=1 #判断有几个主件
    b=[]
    for item in a:
        if len(item)==3 and item[2]==0:
            b.append(item)
        elif len(item)>3:
            for i in range(len(item)//3):
                b.append(item[3*i:3*i+3])
    return b,j,min_m

def arr_get(a,num):
    v=[[0 for _ in range(4)] for _ in range(num)] #money矩阵
    w=[[0 for _ in range(4)] for _ in range(num)] #weights矩阵
    m=-1 #第几个主件
    k=0#用来判断附件个数
    for i in range(len(a)): 
        a[i][0]=a[i][0]//10
        if a[i][2]==0:
            m+=1
            k=0
            main=a[i][0]
            weight=a[i][0]*a[i][1]
            v[m][0]=main
            w[m][0]=weight
        else:
            k+=1
            if k==1: #1个附件
                aux1=a[i][0]
                weight1=a[i][0]*a[i][1]
                v[m][1]=main+aux1
                w[m][1]=weight+weight1
            else:   #2个附件
                aux2=a[i][0]
                weight2=a[i][0]*a[i][1]
                v[m][2]=main+aux2
                w[m][2]=weight+weight2
                v[m][3]=main+aux1+aux2
                w[m][3]=weight+weight1+weight2
    return v,w

n,m=map(int,input().strip().split())
a=[]
for i in range(m):
    item = list(map(int,input().strip().split()))
    a.append(item)
min_m=n
a,num,min_m=order_tune(a,min_m)
#num:主件种类,min_m:购买一个主件最少需要花费多少钱
v,w=arr_get(a,num)
#v:每一种主件与其附件的组合构成的钱数数组,
#w:每一种主件与其附件的组合构成的钱数*重要性数组
weights=[0]*(n//10+1)
for i in range(len(v)):
    for k in range(n//10,min_m//10-1,-1):
        for j in range(4):        
            if k>=v[i][j]:
                weights[k]=max(weights[k],weights[k-v[i][j]]+w[i][j])
print(weights[-1]*10)

3.编程思路

  • 读入数据后,首先使用order_tune()子函数将各附件放在列表中对应主件后;
  • 使用arr_get()得到对应的主件与其附件的组合构成的钱数数组以及钱数*重要性数组;
  • 使用动态规划解决背包问题: weights[k]=max(weights[k],weights[k-v[i]
  • 由于题目中给出每件物品的价格(都是 10 元的整数倍),所以程序中将所有与钱数有关的量都除了10,这样可以大大缩短程序运行时间;
  • 另外设置了变量min_m:购买一个主件最少需要花费多少钱:
    for k in range(n//10,min_m//10-1,-1)
    背包容量最小不是到0,而是设置为min_m//10-1。也可以缩短一部分时间。

2020.4刚做第一遍的时候参考了牛客网陀螺酱做法,这一次在之前基础上完善修改之后,更加直观明了。
欢迎灌水。

4.参考文献

1.https://www.nowcoder.com/profile/479266942/codeBookDetail?submissionId=65570380
2.https://www.nowcoder.com/profile/618300658/codeBookDetail?submissionId=86425486

你可能感兴趣的:(python,动态规划)