202209-2 何以包邮
题目描述
新学期伊始,适逢顿顿书城有购书满 x 元包邮的活动,小 P 同学欣然前往准备买些参考书。
一番浏览后,小 P 初步筛选出 n 本书加入购物车中,其中第 i 本(1≤i≤n)的价格为 ai 元。
考虑到预算有限,在最终付款前小 P 决定再从购物车中删去几本书(也可以不删),使得剩余图书的价格总和 m 在满足包邮条件(m≥x)的前提下最小。
试帮助小 P 计算,最终选购哪些书可以在凑够 x 元包邮的前提下花费最小?
输入格式
从标准输入读入数据。
输入的第一行包含空格分隔的两个正整数 n 和 x,分别表示购物车中图书数量和包邮条件。
接下来输入 n 行,其中第 i 行(1≤i≤n)仅包含一个正整数 ai,表示购物车中第 i 本书的价格。输入数据保证 n 本书的价格总和不小于 x。
输出格式
输出到标准输出。
仅输出一个正整数,表示在满足包邮条件下的最小花费。
样例1输入
样例1输出
样例1解释
购买前两本书(20+90)即可包邮且花费最小。
样例2输入
样例2输出
样例2解释
仅购买第三本书恰好可以满足包邮条件。
样例3输入
样例3输出
样例3解释
必须全部购买才能包邮。
子任务
70% 的测试数据满足:n≤15;
全部的测试数据满足:n≤30,每本书的价格 ai≤104 且 x≤a1+a2+⋯+an。
提示
对于 70% 的测试数据,直接枚举所有可能的情况即可。
python
#01背包 ''' 0-1背包:选择的物品总体积<=背包容量,求价值最大 dp[j]:背包容量为j时,可以装的物品最大价值 此题: 选择的书总价值>=邮费x,求价值最小 dp[j]:邮费限制为j时,可以选择的书的最多价值 ''' n,x=map(int,input().split()) a=[] for _ in range(n): b=int(input()) a.append(b) dp=[0]*(n*x) ss=sum(a) for i in range(n):#书 for j in range(ss,a[i]-1,-1): dp[j]=max(dp[j],dp[j-a[i]]+a[i]) for i in range(x,ss+1): if(dp[i]>=x): print(dp[i]) break '删掉的书的总价格,上限是sum-x,因为总要大于x才能包邮' '通过删掉不同书来改变这个状态,最后找到最接近上限的状态。' ''' 前i本书在j的价格上限内,可以删掉的总价格= max(前i-1本书在j上限可以删掉的总价格 , 前i本书在j-ai的价格上限可以删掉的总价格+ai) =max(不删这本书,删这本书) 如果在上限j删这本书,那么之前就不能删这本书,所以删之前的上限是j-ai '''
#01背包 ''' 既然不能通过枚举所有的情况来找到答案(得分70分) ,那肯定是有一种途径来找到最优解,所以自然的联想到了dp(动态规划);我们再来看一下这个问题,寻找超过包邮条件x的最小数字组合。可以转化为先求书的总价sum,再用sum减去x得y,问题就变成了寻找不超过y(达到包邮条件)的最大数字组合,再用总价减去这个数字组合,即可得到最终答案。寻找不超过y的最大数字组合,这种类型就是典型的背包问题。 比如商品总价格:sum=20+90+60+60=230 x= 100(满100包邮) y=230-100=130 寻找在130范围内的最大商品.当然我们从开始的思路就是逆向来的,所以最后回溯算法得到的列表也是不包含题目答案的答案. ———————————————— maxValue[商品][背包容量] ''' n,x =map(int,input().split()) price=[0]+[i for i in map(int,input().split())] pre =sum(price) #计算总价钱 price.sort() #可以省略 y =[i for i in range(pre-x+1)]#从0到y 也就是可以删去的价钱数目 maxValue =[ [0 for i in range(pre -x+1)] for j in range(n+1)] #第一行为0行 第一列为0列 #一共n+1行 每行都是一个0-pre -x+1的0列表 for i in range(1,len(price)+1):#相当于物品行 遍历所有物品 weight = price[i-1] #重量 value =price[i-1] #价值 for j in range(len(y)):#删去上限为j maxValue[i][j]=maxValue[i-1][j] #0/1背包主要代码① #商品i 删去上限为j 时最大价值 if j >= weight: #如果背包重量大于=当前物品的重量 就相当于我们可以还以塞其他物品 maxValue[i][j] = max(maxValue[i-1][j],maxValue[i-1][j-weight]+value) #0/1背包主要代码② #没有加i行物品的价值 , 在加入上一行物品前提下,背包重量腾出i行物品的重量+i行物品的价值 # 输出看看我们的maxValue矩阵 #print(pre - maxValue[-1][-1]) # for i in range(n+1): # print(maxValue[i]) #回溯寻找 def huishuo(maxValue,items): sequence=[] #i行代表物品行 j列 代表weight i =len(maxValue)-1 j =len(maxValue[0])-1 while i >0 and j >0 : if maxValue[i][j] == maxValue[i-1][j]: #相等代表没有加进来这个物品 i -=1 else: sequence.append(price[i-1]) #添加进来这个物品 因为price是从1开始 所以i-1 j =j- price[i-1] # j 减去 这个东西的重量 (没放进去这个商品的书包的容量) i -=1 #往上一行寻找 return list(reversed(sequence)) #因为回溯寻找 最后要将结果倒置 result= huishuo(maxValue,price) # print(result) #以下结果为我们真正题目要求的结果 final =[] for i in range(len(price)): if price[i] not in result: final.append(price[i]) print(sum(final))

浙公网安备 33010602011771号