华为OD机试
任务最优调度
题目
【任务最优调度】给定一个正整数组表示待系统执行的任务列表,数组的每一个元素代表一个任务,元素的值表示该任务的类型。请计算执行完所有任务所需的最短时间。
任务执行规则如下:
1、任务可以按任意顺序执行,且每个任务执行耗时间均为1个时间单位。
2、两个同类型的任务之间必须有长度为N个单位的冷却时间,比如N为2时,在时间K执行了类型3的任务,那么K+1和K+2两个时间不能执行类型3任务。
3、系统在任何一个单位时间内都可以执行一个任务,或者等待状态。说明:数组最大长度为1000,速度最大值1000。
输入描述:
第一行记录一个用半角逗号分隔的数组,数组长度不超过1000,数组元素的值不超过1000第二行记录任务冷却时间,N为正整数,N<=100。
输出描述:
输出为执行完所有任务所需的最短时间。
示例:
输入
2,2,2,3
2
输出
7
思路
模拟任务调度的过程
首先导致时间利用率低的是冷却时间,只要将冷却时间被合理利用则整体时间就会越低。因为相同任务越多的产生冷却时间的也就越多,而相同任务越少的可以作为对前面产生冷却时间利用的合理利用,所以相同任务多的先分配相同任务少的后分配。
分配时可以使用一个数据结构记录当前剩余可用的空闲时间(包括冷却时间)供后面任务使用,为了快速锁定任务调度时间可以使用数据结构TreeSet作为空闲时间的存储
代码
@Test
public void test32(){
Scanner scanner=new Scanner(System.in);
String str=scanner.nextLine();
HashMap<Integer,Integer> map=new HashMap<>();
Arrays.stream(str.split(",")).mapToInt(Integer::parseInt).forEach(el->map.merge(el,1, Integer::sum));
Integer nums[] =map.values().stream().sorted((x,y)->y-x).toArray(Integer[]::new);//按不同任务多少降序排序
TreeSet<Integer> times=new TreeSet<>();//记录当前从1到最大的使用时间之间的空闲时间
int n=scanner.nextInt();//n为冷却时间
IntStream.range(1,n+1).forEach(times::add);//设置初始空闲时间为1~n
int maxTime=Integer.MIN_VALUE;//记录任务被调度的最长时间
for(int index=0;index<nums.length;index++){//遍历每一种任务
Integer temp=nums[index],position=times.first();//position是当前任务执行时间
while (temp>0){
if(times.ceiling(position)==null){//找不到合适时间对时间进行扩容
IntStream.range(maxTime+1,maxTime+n+2).forEach(times::add);//从占用最大位置时间开始扩容
}
position=times.ceiling(position);//查找到下一个空闲时间
maxTime=Math.max(maxTime,position);//记录任务调度最久的时间
times.remove(position);//该空闲时间已经使用移除掉
position+=n+1;//获取下一个可以调度该任务的最低时间
temp--;
}
}
System.out.println(maxTime);
}