POJ 1193 链表 + 二叉堆

题意

传送门 POJ 1193 内存分配

题解

设进程请求数为 Q Q Q,朴素的方法复杂度 O ( Q N ) O(QN) O(QN),显然难以胜任。算法的瓶颈在于分配内存时 O ( N ) O(N) O(N) 的遍历。

考虑离散化,实际上内存最多分为 O ( Q ) O(Q) O(Q) 个地址片,那么单次求解所分配空闲地址片的首地址复杂度可以降为 O ( Q ) O(Q) O(Q)。实现上,使用链表按地址顺序维护正在运行的地址片,那么空闲的地址片大小可以通过一次遍历链表,对相邻地址片作差求解。考虑到地址片在规定的运行结束时间释放内存,为了方便删增,使用二叉堆按照运行结束时间维护地址片在链表中的位置。总时间复杂度为 O ( Q ⋅ ( Q + log ⁡ Q ) ) O(Q\cdot(Q+\log Q)) O(Q(Q+logQ))

总运行时间最长达到 O ( Q N ) O(QN) O(QN),再次考虑离散化,实际上内存发生变化的时间节点只有 O ( Q ) O(Q) O(Q)。位于等待队列的请求,仅当出现内存片结束运行时才会分配内存,故将内存片结束运行时间看做离散的时间节点,注意结束运行时间相同的内存片要同时释放。进程请求时刻,直接进行内存分配,故进程请求时刻也看做离散的时间节点。不断维护离散的时间节点,模拟内存分配过程即可。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 10005;
struct P
{
#define pre(x) list[x].pre
#define nxt(x) list[x].nxt
#define s(x) list[x].s
#define m(x) list[x].m
    int s, m, pre, nxt;
} list[maxn];
struct P2
{
    int id;
    ll t;
    bool operator<(const P2 &b) const { return t > b.t; }
};
priority_queue<P2> pq;
queue<pii> wq;
ll cur;
int N, cnt, head, tail, tot;

void init()
{
    tot = 2, head = 1, tail = 2;
    nxt(head) = tail, s(head) = m(head) = 0;
    pre(tail) = head, s(tail) = N;
}

int insert(int p, int s, int m)
{
    int q = ++tot;
    s(q) = s, m(q) = m;
    pre(nxt(p)) = q, nxt(q) = nxt(p);
    nxt(p) = q, pre(q) = p;
    return q;
}

void remove(int p) { pre(nxt(p)) = pre(p), nxt(pre(p)) = nxt(p); }

bool in(int m, int p)
{
    for (int i = head; i != tail; i = nxt(i))
    {
        int d = s(nxt(i)) - (s(i) + m(i));
        if (d >= m)
        {
            int id = insert(i, s(i) + m(i), m);
            pq.push(P2{id, cur + p});
            return 1;
        }
    }
    return 0;
}

void out()
{
    cur = pq.top().t;
    while (pq.size() && pq.top().t == cur)
    {
        int p = pq.top().id;
        pq.pop();
        remove(p);
    }
    while (wq.size() && in(wq.front().first, wq.front().second))
        wq.pop();
}

int main()
{
    scanf("%d", &N);
    init();
    int t, m, p;
    while (~scanf("%d%d%d", &t, &m, &p) && (t | m | p))
    {
        while (pq.size() && t >= pq.top().t)
            out();
        cur = t;
        if (!in(m, p))
            ++cnt, wq.push(pii(m, p));
    }
    while (pq.size())
        out();
    printf("%lld\n%d\n", cur, cnt);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值