ural(Timus) 1037. Memory Management

数据结构:堆

题目

请你写一个内存管理系统。 内存中有30000个块,编号为1..30000。 当操作系统需要内存时内存管理系统会找出编号最小的空闲块,向里面写入数据。 操作系统还会会发出指令读取某个编号的内存块。如果目标块空闲,读取失败,否则读取成功。 一开始所有块都是空闲块。被写入数据之后就不是空闲块了。 如果一个块在600秒内没有被写入或读取,这块内存自动清空,变为空闲块。 本题中不会出现内存块不够用的情况。

输入格式

每行一个要求,可能是申请内存或读取。

申请内存的格式如下: T + T表示这条请求收到时的时间,是不大于65000的整数,以秒为单位。

读取内存的格式如下: T . N T表示这条请求收到时的时间,N表示需要读取的内存块的编号(1-30000)。 操作系统的请求不会超过80000个。

请求按照时间增序排序。

输出格式

每行回答一个请求。 对于申请内存的请求,回答一个整数-你分配给它的内存块的编号。 对于读取内存的请求,如果成功输出+,失败输出-。

思路:这题的先后逻辑关系还是要搞清楚的,否则容易错。

1.我们开辟两个堆,一个是空闲堆,一个占用堆,两个都是小顶堆。

2.空闲堆的关键字就是内存单元的编号,这样查找编号最小的空闲单元就是O(1),维护堆是O(logn)

3.占用堆每个元素需要记录两个元素,一个是内存单元的编号一个是回收该单元的时间,关键字是回收时间

4.另外我们开辟一个数组time,记录每个内存单元的回收时间,如果i单元是空闲的那么time[i]=-1

5.另外内存的回收时间是不断变化的,当一个内存还被占用时读取了它,会重新计时,从那时起再加600才是它的回收时间,所以在占用堆中的元素一旦被读取就要改变回收时间,那么

其在堆中的时间就要改变,要调整,其实就是在元素为根的子树内调整(因为可知一旦重新计时回收时间一定是大于或与原来的时间,该元素应该沿子树方向下滑)。为了知道占用堆中每个元素具体在堆中的什么位置,需要一个数组来记录pos,pos[i]=m,表示i号内存在堆中的第m个下标里存放。因此查询一个内存是否能访问,为O(1),访问后要调整为O(logn)

6.到达了回收时间,占用堆中过期的元素就要被回收到空闲堆,所以在占用堆中涉及了删除头节点的操作。那什么时候删除过期元素呢?就是读入每条指令的时间后,不管读入的是什么操作,都要先清除掉过期的元素——例如申请内存操作,要先把过期单元放回去申请,例如查询操作,要先清除过期元素才能判断该元素是否还被占用

7.在空闲堆中涉及删除和插入操作所以写了两个函数 insertheap(),delheap()

8.在占用堆中涉及删除,插入和调整操作,但是删除和调整函数可以合并为一个,另外删除相当于在根开始调整,而调整是在其子树上开始调整,因而合并为updata(),另外的是insetHeap()

9.在占用堆中的操作,无论是什么操作,都要记得维护pos数组,不要丢失了它的记录信息

代码有点长,其实重写了一次,之前的代码不知道哪里有小bug一直卡在第4组数据中过不了

这题还是要注意一些细节的,否则就是卡了也找不出来了,因为在两个堆中交换元素太频繁了

#include <cstdio>
#include <cstring>
const int N = 30000;
const int T = 600;

int free,busy;
int heap[N+10];
int time[N+10];
int pos[N+10];
struct HEAP
{
    int time,n;
}Heap[N+10];

void init()
{
    free=N;
    for(int i=1; i<=N; i++) heap[i]=i;
    memset(time,-1,sizeof(time));
    memset(pos,-1,sizeof(pos));
    busy=0;
    memset(Heap,-1,sizeof(Heap));
}

void updata(int p)
{
    struct HEAP tmp=Heap[p];
    int key=Heap[p].time , n=Heap[p].n;
    int par,son,m;
    for(par=p,son=par*2; son<=busy; son=par*2)
    {
        if(son<busy && Heap[son+1].time < Heap[son].time) son++;
        if(key < Heap[son].time) break;
        m=Heap[son].n;
        pos[m]=par;
        Heap[par]=Heap[son];
        par=son;
    }
    pos[n]=par;
    Heap[par]=tmp;
}

int delHeap()
{
    int n=Heap[1].n; //要返回的内存单元
    if(busy==1)
    {
        time[n]=pos[n]=-1;
        busy=0;
        return n;
    }
    time[n]=pos[n]=-1;
    Heap[1]=Heap[busy--];
    updata(1); //从堆的1号节点开始更新
    return n;
}

void insertheap(int n)
{
    int key,par,son;
    heap[++free]=n;
    key=n;
    for(son=free,par=son/2; par>=1; par=son/2)
    {
        if(key > heap[par]) break;
        heap[son]=heap[par];
        son=par;
    }
    heap[son]=key;
}

void check(int Time)
{
    while(busy>0 && Heap[1].time < Time)
    {
        int n=delHeap();
        insertheap(n);
    }
}

void delheap()
{
    int key,par,son;
    key=heap[free];
    heap[1]=heap[free--];
    for(par=1,son=par*2; son<=free; son=par*2)
    {
        if(son<free && heap[son+1] < heap[son]) son++;
        if(key < heap[son]) break;
        heap[par]=heap[son];
        par=son;
    }
    heap[par]=key;
}

void insertHeap()
{
    struct HEAP tmp=Heap[busy];
    int key=Heap[busy].time , n=Heap[busy].n;
    int par,son,m;
    for(son=busy,par=son/2; par>=1; par=son/2)
    {
        if(key >= Heap[par].time) break;
        m=Heap[par].n;
        pos[m]=son;
        Heap[son]=Heap[par];
        son=par;
    }
    pos[n]=son;
    Heap[son]=tmp;
}

int main()
{
    int Time; char op[5]; int index;
    init();
    while(scanf("%d",&Time)!=EOF)
    {
        check(Time); //将占用堆过期元素取出并且放回空闲堆
        scanf("%s",op);
        if(op[0]=='+')
        {
            index=heap[1];
            delheap();
            struct HEAP tmp;
            int num;
            tmp.n=index; tmp.time=Time+T-1;
            time[index]=Time+T-1;
            busy++;
            pos[index]=busy;
            Heap[busy]=tmp;
            insertHeap();
            printf("%d\n",index);
        }
        else
        {
            scanf("%d",&index);
            if(time[index]==-1 && pos[index]==-1)
            {
                printf("-\n");
                continue;
            }
            time[index]=Time+T-1;
            index=pos[index];
            Heap[index].time=Time+T-1;
            updata(index);
            printf("+\n");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3002810.html