这个问题一直放在我的 todo list里,今天还是靠陈博大佬给整出来了。
题目
大概意思是,有一批工单号,每个工单有一个时效SLA,也有一个得分score,每处理一个工单耗时一个单位。问应如何按时间处理这些工单号使得收益最大。
牛客网找的样例:
错误思路
在机试的时候立马想到的是优先处理快过期的,即按时间排序,时间相同的按得分降序。然后沿时间处理,累计得分。
但是样例一直只能通过45,百思不得其解,后来牛客网看到有大佬说下面这种情况
所以说并非每次优先处理即将过期的,因为可能有稍晚过期但得分高的工单,我们应该去处理这个高分工单【如 2 89】。
又错误思路
按奖励排序 --> 选出奖励最大的以及其时效 N --> 取所有小于等于该时效的TOP N --> 一次挑选结束,把所有小于该失效的都判为过期 -->重复去后面有效前内执行前面的步骤,直到最后时刻,退出循环
错误原因在于若得分次高的一些工单的SLA都为1,那么直接的TOP N将不成立
SLAS = list(map(int, input().split()))
scores = list(map(int, input().split()))
works = list(zip(SLAS, scores))
T = 0
ans = 0
works.sort(key=lambda x:x[1], reverse=True)
while works:
t = works[0][0]
N = t - T ## 可选工单数
cnt = 0
i = 0
while cnt < N and i < len(works):
if works[i][0] <= t:
ans += works.pop(i)[1]
cnt += 1
else:
i += 1
works = [work for work in works if work[0]>t] ## 去除过期的工单
T = t
print(ans)
## test 1
##1 1 3 3 2 2 6
##6 7 2 1 4 5 1
## test 2
##1 1 2 2 3
##7 5 89 100 6
正正正正解!!!
参考力扣630. 课程表 III
整体思路为:优先选择SLA小的,但若存在后面时间不够SLA但分数很高的单子,就要替换掉原来的选择。
具体的做法为:先按SLA排序,维护一个小根堆代表已经选的单。优先选SLA小的单子,当时间不够当前单时,当前单得分和已选单的最小得分pick,如果得分大则用该单子替换掉小得分单,否则忽略该单。这种做法能够一直保持当前时刻所选的所有单子得分和最大,即时刻保持最优解。
import heapq
SLAS = list(map(int, input().split()))
scores = list(map(int, input().split()))
works = list(zip(SLAS, scores))
works.sort(key=lambda x:x[0])
q = []
t = 0
ans = 0
for work in works:
if work[0] > t:
heapq.heappush(q, work[1])
t += 1
ans += work[1]
else:
minscore = heapq.heappushpop(q, work[1])
ans += work[1] - minscore
print(ans)
## test 1
##1 1 3 3 2 2 6
##6 7 2 1 4 5 1
## test 2
##1 1 2 2 3
##7 5 89 100 6