[HNOI2003] 操作系统
题目描述
写一个程序来模拟操作系统的进程调度。假设该系统只有一个 CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的。其中运行优先级用自然数表示,数字越大,则优先级越高。
如果一个进程到达的时候 CPU 是空闲的,则它会一直占用 CPU 直到该进程结束。除非在这个过程中,有一个比它优先级高的进程要运行。在这种情况下,这个新的(优先级更高的)进程会占用 CPU,而老的只有等待。
如果一个进程到达时,CPU 正在处理一个比它优先级高或优先级相同的进程,则这个(新到达的)进程必须等待。
一旦 CPU 空闲,如果此时有进程在等待,则选择优先级最高的先运行。如果有多个优先级最高的进程,则选择到达时间最早的。
输入格式
输入包含若干行,每一行有四个自然数(均不超过 1 0 8 10^8 108),分别是进程号,到达时间,执行时间和优先级。不同进程有不同的编号,不会有两个相同优先级的进程同时到达。输入数据已经按到达时间从小到大排序。输入数据保证在任何时候,等待队列中的进程不超过 15000 15000 15000 个。
输出格式
按照进程结束的时间输出每个进程的进程号和结束时间。
样例 #1
样例输入 #1
1 1 5 3
2 10 5 1
3 12 7 2
4 20 2 3
5 21 9 4
6 22 2 4
7 23 5 2
8 24 2 4
样例输出 #1
1 6
3 19
5 30
6 32
8 34
4 35
7 40
2 42
题目纯模拟,就是很麻烦
这道题看起来是提高+/省选-实际上一点也不难,主要涉及的难点是优先队列和重载运算符。
优先队列:
首先优先队列虽然叫队列,但是本质上是用堆来维护的。
优先队列与普通队列不同,它的堆头是队列中最大(最小)元素。
下面是优先队列的基本用法
1.priority_queue<类型> q;//定义
2.q.push(元素);//入队,时间复杂度为logn
3.q.pop();//出队,出队头
4.q.top();//获取堆顶元素
5.q.size();//获取元素个数
6.q.empty();//判空,空返回1
这些就是常用的操作,当然优先队列默认是大根堆,所以如果想要让堆顶变为最小的有两种方法,我比较推荐第二种,更加简单,就是在入队时把入队元素变成负数,然后出队时在变回来(虽然简单,但是用处仅限于数字 )
如果需要小根堆的写法,可以在网上搜,我先写一个int类型的。
priority_queue<int,vector<int>,greater<int>> a;
注意:这里本蒟蒻用的c++版本较高,如果低版本请将两个或多个连续的大于号或者小于号用空格隔开,不然会报错(会把两个小于号/大于号当作位运算)
好的,讲完了优先队列似乎就可以做了,但是你会发现这东西需要综合考虑,所以得用结构体。
然后你把它套进去就直接报错了。
原因很简单,优先队列不知道你按啥规则。
重载运算符
所以就要用到重载运算符了
struct pr{//这是我写的结构体
int id,time1,time2,lv;
bool operator<(const pr& tmp) const{//重载运算符
if(lv!=tmp.lv){
return lv<tmp.lv;
}
return time1>tmp.time1;
}
};
重载运算符作用简单,但是用处很大,现在,两个结构体变量就可以直接使用 < < <了,比如这样一段代码:
pr a,b;
a.id=1;
a.time1=10;
a.time2=10;
a.lv=7;
b.id=2;
b.time1=14;
b.time2=10;
b.lv=4;
cout<<b<a;
可以正常输出。
思路
模拟每个进程进入,进入之后先把它进入之前的所有可以运行的进程全部运行(优先队列里的),然后把它放进优先队列就可以了。
最后记得清空队列。
代码
注意:优先队列需要重载的是小于号
这样就能给出完整代码了:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+10;
const int N3=1e3+10;
struct pr{//结构体
int id,time1,time2,lv;//分别为编号、开始时间、需要时间、优先级
bool operator<(const pr& tmp) const{//重载运算符
if(lv!=tmp.lv){
return lv<tmp.lv;
}
return time1>tmp.time1;
}
};
priority_queue<pr> q;//优先队列
int a,b,c,d;
ll now_time=1;
int main(){
while(cin>>a>>b>>c>>d){//多组输入,用while(cin>>)
while(!q.empty()&&now_time+q.top().time2<=b){//当前这个程序到来之前,把可以执行的全都执行了。
now_time+=q.top().time2;
printf("%d %lld\n",q.top().id,now_time);
q.pop();
}
if(!q.empty()){//处理执行一半被切断的情况。
pr t=q.top();
q.pop();
t.time2-=b-now_time;
q.push(t);
}
now_time=b;//更新时间
q.push({a,b,c,d});
}
while(!q.empty()){//这里不输出会有问题。
now_time+=q.top().time2;
printf("%d %lld\n",q.top().id,now_time);
q.pop();
}
return 0;
}
我后面会单独出一片关于重载运算符的讲解,所以这里就不多讲了。