HNOI2003 操作系统

我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1216

不兹磁多线程的系统不是好系统>_<

对于每个进程,我们都记录下关于它的五个参数:进程号,起始时间,持续时间,终结时间以及优先级。

按照题意,优先级越大越应优先执行,同优先级的比起始时间,用堆来维护已经进来排队的进程,然后按题意模拟即可。

因为学长说想要\(NOI\)金牌,堆肯定是要会手写的,所以我一直都用手写堆,而且个人觉得\(C++\)\(stl\)除了\(vector\)以外都可以手动模拟的……

时间复杂度:\(O(n log n)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=350000;

int n=1;

struct AK {
    int id,st,ed,lst,lv;
}a[maxn];

bool cmp_ed(AK a,AK b) {
    return a.ed<b.ed;
}

bool check(int x,int y) {
    if(a[x].lv==a[y].lv)return a[x].st<a[y].st;
    return a[x].lv>a[y].lv;
}//判断x进程是否比y进程优秀

struct heap {
    int tot;
    int tree[15005];

    void ins(int u) {
        tree[++tot]=u;int now=tot;
        while(now!=1)
            if(check(tree[now],tree[now>>1]))
                swap(tree[now],tree[now>>1]),now>>=1;
            else break;
    }//将一个元素插入堆

    void pop() {
        tree[1]=tree[tot--];
        int now=1;
        while(now<<1<=tot) {
            int son=now<<1|1;
            if((now<<1|1)>tot||check(tree[now<<1],tree[now<<1|1]))
                son=now<<1;
            if(check(tree[now],tree[son]))break;
            else swap(tree[now],tree[son]),now=son;
        }
    }//从堆顶弹一个元素出去
}T;

int main() {
    while(~scanf("%d%d%d%d",&a[n].id,&a[n].st,&a[n].lst,&a[n].lv))
        n++;//先把所有进程都读入
    a[n].st=2147483647;//安排一个很靠后时间进来的进程把堆里的进程全部pop出去
    for(int i=1;i<n;i++) {
        T.ins(i);int sum=0;//让i进程开始排队,sum为从i号进程的开始时间起已经用了多少时间
        while(T.tot&&a[i].st+sum+a[T.tree[1]].lst<=a[i+1].st) {//如果可以把当前优先级最高的进程做完
            sum+=a[T.tree[1]].lst;
            a[T.tree[1]].ed=a[i].st+sum;
            T.pop();
        }
        if(T.tot)a[T.tree[1]].lst-=a[i+1].st-a[i].st-sum;//如果做不完当前优先级最高的进程,那么在下一个进程进来之前能做多少是多少
    }
    sort(a+1,a+n,cmp_ed);//按结束时间排序,输出答案
    for(int i=1;i<n;i++)
        printf("%d %d\n",a[i].id,a[i].ed);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKMer/p/9097184.html