蓝桥杯2021年第十二届真题第二场-负载均衡

题目

题目链接

题解

优先队列。(感觉不好想,以为是差分数组,但是维度太大)


每个计算机都是独立的,所以只要解决了一个计算机如何更新算力,多个也就不在话下了。

整体思路,(以单个计算机为对象考虑)每遍历到一个任务时,我们要比较当前计算机的算力与当前任务消耗的算力的大小关系,如果前者大于等于后者,则可以执行任务,反之不行。如果可以执行任务,那么我们就让v(计算机当前的算力)减去d(当前任务消耗的算力)。

但是我们还应当考虑该任务刚开始执行的时刻a,是否已经有一些任务已经完成了,也就是是否有一些任务可以释放自己占有的算力。只有结束时间早于或等于a的任务才会释放占有的算力。


如何保存和找到结束时间小于等于a的任务呢?我们可以使用优先队列动态存储比当前任务开始时间早的任务的相关信息。

通过小根堆动态存储任务的结束时间,当执行到开始时间为a的任务时,如果堆顶元素的结束时间小于等于a,则说明堆顶元素对应的任务在a之前已经结束了,那么堆顶元素对应的任务占用的算力就可以释放了,我们让v+=堆顶元素对应的任务占用的算力,再弹出堆顶元素,表示该任务完成,接下来的任何事情都和该堆顶元素无关了。不断如此重复,直至队列空了,或者遇到结束时间大于a的堆顶元素了,那么也说明队列后面的元素的结束时间必然也大于a

不断地出队操作,不断地更新v,当出队操作结束说明v已经更新成了当前时刻计算机的算力了。


这时候,我们才可以用当前任务的d(消耗算力)与当前时刻的计算机算力v作比较,如果d>v,那么任务无法执行输出-1;反之,任务可以执行,既然开始执行了,那就把该任务的结束时间入队,让v-=d作为该任务开始执行后的计算机算力,并输出这个v


对于不同的任务,会存在不同的d。在不断出队的阶段,我们要让v不断加上对应任务的d,所以这个优先队列不仅要动态存储每个未结束的任务的结束时间,还要保存其对应的算力消耗值。


这是完成了更新一个计算机算力的思路,但是其实存在多个计算机算力的更新。

每个计算机都对应一个优先队列就好了,优先队列的索引就是计算机的编号。

这样一来整个算法就完整了。

代码

#include<bits/stdc++.h>
#define PII pair<int, int>
using namespace std;
const int N = 2e5+10;

priority_queue<PII, vector<PII>, greater<PII> > q[N]; // 改写成小根堆 
// STL priority_queue 是默认大根堆,比较符号默认是 <
int v[N];

int main()
{
	int n, m, a, b, c, d;
	cin >> n >> m;
	for (int i = 1;i <= n;i ++) cin >> v[i];
	
	while (m --) {
		cin >> a >> b >> c >> d;
		
		while (q[b].size ()) {  
			int end_time = q[b].top().first;
			int consumption = q[b].top().second;
			
			if (end_time > a) break; // 如果堆顶(最早结束)的任务的结束时间都大于当前任务的开始时间 
			
			v[b] += consumption;
			q[b].pop();
		}
		// 上面的整个while就是将a时刻之前结束的任务消耗的算力都加到v上,得到a时刻计算机的算力 (对单个计算机而言) 
		
		if (v[b] >= d) { // 如果当前时刻计算机算力大于等于当前任务的算力消耗 
			q[b].push({a + c, d}); // 将该任务的信息加入到队列中 
			v[b] -= d; // 更新计算机算力
			cout << v[b] << endl;
		} else {
			cout << -1 << endl; // 算力不足,无法完成此次任务 
		}
	}

	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不牌不改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值