工单调度策略
题目描述
-
当小区通信设备上报警时,系统会自动生成待处理的工单,工单调度系统需要根据不同的策略,调度外线工程师(FME)上站去修复工单对应的问题。
-
根据与运营商签订的合同,不同严重程度的工单被处理并修复的时长要求不同,这个要求被修复的时长我们称之为SLA时间。
-
假设华为与运营商A签订了运维合同,部署了一套调度系统,只有1个外线工程师(FME),每个工单根据问题严重程度会给一个评分,在SLA时间内完成修复的工单,华为员工获得工单对应的积分,超过SLA完成的工单不获得积分,但必须完成该工单,运营商最终会根据积分付款。
-
请设计一种调度策略,根据现状得到调度结果完成所有工单,让这个外线工程师处理的工单处理的工单获得的总积分最多。
-
假设从某个调度时刻开始,当前工单数量N,不会产生新的工单,每个工单处理修复耗时为1小时。请设计你的调度策略,完成业务目标。
-
不考虑外线工程师在小区之间行驶的耗时。
输入
输出
import java.util.*;
/**
*
* 这个工单调度策略的思路是,将所有工单按照评分从大到小排序,然后遍历每个工单,尝试将其分配给外线工单程师进行修复。
* 为了保证在SLA到期完成修复,我们需要维护一个优先队列(堆)仓库可用的时间,即已经完成其他工单还剩余来的时间。
* 如果当前工单的SLA时间小于等于可用的时间时间的轻轻的,则可以将其分配给外线工程师进行修复,并且更新可用时间完成。
* 否则,需要等待直到有足够的可用时间。如果遍历完所有工单后,仍有剩余的可用时间,则可以继续完成完成工单,但不会获得统计的积分。
* 最终输出总共获得的积分即可。
* <p>
* 注意,这个算法的时间复杂度为O(nlogn),因为需要进行一次排序操作,并且每次插入和删除元素时需要调整堆的结构。
*/
public class OdAb37 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); // 工单数量
int[][] orders = new int[n][2]; // 二维数组存储每个工单的SLA时间和积分
for (int i = 0; i < n; i++) {
orders[i][0] = scanner.nextInt();
orders[i][1] = scanner.nextInt();
}
Arrays.sort(orders, (a, b) -> { // 按照工单的评分从大到小排序
return b[1] - a[1];
});
PriorityQueue<Integer> pq = new PriorityQueue<>(); // 使用优先队列(堆)存储可用的时间
int time = 0; // 当前时间
int points = 0; // 总共获得的积分
for (int i = 0; i < n; i++) {
int sla = orders[i][0]; // 当前工单的SLA时间
int score = orders[i][1]; // 当前工单的评分
if (pq.size() < sla) { // 如果可用时间不够当前工单的SLA时间,则需要等待
pq.offer(sla); // 将该SLA时间加入队列
points += score; // 能够修复该工单,获得对应积分
} else if (pq.peek() > sla) { // 如果队列中最小的SLA时间比当前工单的SLA时间大,则可以修复该工单
int availableTime = pq.poll(); // 取出可用的最小SLA时间
pq.offer(sla); // 将该SLA时间加入队列
points += score; // 能够修复该工单,获得对应积分
time -= availableTime - sla; // 更新当前时间
} else { // 如果队列中已有的可用时间都比当前工单的SLA时间小,则无法修复该工单,不获得积分
continue;
}
time++; // 完成一个工单,更新当前时间
}
System.out.println(points); // 输出总共获得的积分
}
}