【洛谷】2022春数据结构期末模拟赛G题-“推销员”题解

题目链接

U220508 推销员

要想获得最大收益,那么卖出的商品应该尽可能晚,利润尽可能高,对此我们有两种方法,第一种是对过期时间进行排序,先处理过期时间短的商品;第二种是对商品利润进行排序,先处理利润高的商品。

方法一:优先队列

算法思路

按照过期天数从小到大进行排序,用一个优先队列来模拟需要卖出的商品,优先队列中的元素个数表示已经过去的天数。我们对排序后的商品列表进行遍历,若当前商品的过期时间大于队列中元素个数,说明售卖完队列中的商品后该商品依然不会过期,因此可以将此商品加入队列;若等于,则需要判断此商品的价值是否大于队头元素的利润(队头元素利润最低)。此外,并不会出现当前商品的过期时间小于队列中元素个数的情况,设当前商品的过期时间为n,则队列中的元素个数至少为n+1,那么队列中的最后一个元素的过期时间应至少为n+1,而过期天数由小到大进行排序,因此不可能出现此情况。

实现代码
import heapq as h

n = int(input())
ls = []
for i in range(n):
    ls.append(list(map(int, input().strip().split())))
ls.sort(key=lambda x:x[1])
q = []
for goods in ls:
    if goods[1] > len(q):
        h.heappush(q, goods)
    elif goods[1] == len(q):
        if goods[0] > q[0][0]:
            h.heappop(q)
            h.heappush(q, goods)
ans = 0
for i in q:
    ans += i[0]
print(ans)

方法二:并查集

算法思路

按照商品利润从大到小进行排序,然后依次卖出商品。商品可以在过期日期前任意一天卖出,为了保证不错过短过期时间的商品,我们尽可能晚地售卖商品。若当前商品的过期日期这天还没有商品卖出,那么就将该商品安排在这一天卖出;若当前商品的过期日期这天有商品卖出,则一定是之前利润更高的商品安排在这天卖出,因此我们需要将此商品安排在该日期之前售出,如果该日期前还有空余的日期,那么就在空余的日期售出,如果没有空余日期则不售出该商品。我们采用并查集的数据结构来实现此算法,设置一个日期并查集p,find(i)表示该日期前最晚能售卖的日期,初始时p[i]=i,表示该日期上没有商品售出,当第i天有商品售出时,则p[find(i)]应该等于find(i)-1,表示find(i)天后所有日期都有商品售卖。由于过期时间大于或等于商品个数的商品一定能售卖,因此我们不需要判断此类商品。

实现代码
def find(x):
    if p[x] == x:
        return x
    else:
        p[x] = find(p[x])
        return p[x]
    
n = int(input())
ls, ans = [], 0
for i in range(n):
    ls.append(list(map(int, input().strip().split())))
ls.sort(key=lambda x:x[0], reverse=True)
p = [i for i in range(n)]
for goods in ls:
    if goods[1] >= n:
        ans += goods[0]
        continue
    if find(goods[1]) > 0:
        ans += goods[0]
        p[find(goods[1])] = find(goods[1]) - 1
print(ans)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值