UVA ~ 822 ~ Queue and A (STL + 模拟)

题意:你的任务是模拟一个客户中心运作情况。客服请求共有n (1<=n<=20) 种主题,每种主题用5个整数描述: tid,num,t0,tdt,其中tid 为主题的唯一标识符,num为该主题的请求个数,t0为第一个请求的时刻,为处理一个请求的时间,dt 为相邻两个请求之间的间隔(为了简单情况,假定同一个主题的请求按照相的间隔到达)。

客户中心有m (1<=m<=5) 个客服,每个客服用至少3个整数描述: pid,k,tid1,tod2...tidk,表示一个标识符为pid的人可以处理k种主题的请求,按照优先级从大到小依次为tid1,tid2,...,tidk。当一个人有空时,他会按照优先级顺序找到第一个可以处理的请求。如果有多个人同时选中了某个请求,上次开始处理请求的时间早的人优先; 如果有并列,id小的优先。输出最后一个请求处理完毕的时刻。

思路:这个题看起来乱糟糟的,不知道该以什么为主线去模拟,想了好半天也没想出来,只好去看别人的博客了。找到了一篇讲的还不错的,就学习了一波,原博客链接:[刷题]算法竞赛入门经典(第2版) 5-13/UVa822 - Queue and A

我讲一下自己的看法把:我们以时间为主线一步步的往后模拟,更新状态,我可以把客服们处理请求看作在时间轴上的一些线段,其实线段的中间部分是没有用的,而线段的端点位置是有用的,因为他可能接到新的请求,所以我们让时间不一秒秒的往后走,而是跳着走,只去访问有用的时间点,然后更新任务状态。

我们用map<int, Topic>用该主题的tid编号对应,该主题的请求。Topic中用t保存请求的间隔时间,queue<int> table保存所有任务的开始时间。

person[]数组保存客服信息,st表示上一次任务的开始时间,time表示处理完当前请求的时间。

具体解释看代码把:

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Topic
{
    int t;//处理一个请求的时间
    queue<int> table;//该主题的所有请求的开始时间表
};
map<int, Topic> topic;//主题的tid对应请求
struct Person
{
    int pid, k, time, st, tid[25];
    bool operator < (const Person& that) const
    {
        if (st != that.st) return st < that.st;
        return pid < that.pid;
    }
};
int N, M;//N个请求,M个人
int main()
{
    int Scenario = 1;
    while (~scanf("%d", &N) && N)
    {
        int time(INF), ans(0);//当前时间,答案
        topic.clear();
        for (int i = 0; i < N; i++)
        {
            int tid, num, t0, t, dt;
            Topic temp;
            scanf("%d%d%d%d%d", &tid, &num, &t0, &temp.t, &dt);
            time = min(time, t0);//维护开始时间
            Topic& x = (topic[tid] = temp);
            while (num--) x.table.push(t0), t0 += dt;//该主题所有请求的开始时间放入队列
        }
        scanf("%d", &M);
        vector<Person> person(M);//定义一个长度为M的Person类型的一个数组
        for (int i = 0; i < M; i++)
        {
            scanf("%d%d", &person[i].pid, &person[i].k);
            for (int j = 0; j < person[i].k; j++)
                scanf("%d", &person[i].tid[j]);
        }
        //time表示当前时间,整个模拟过程主要以时间为线索
        while (N)//还有请求未完成
        {
            int jumpt(INF);//所有人的下次时间点
            sort(person.begin(), person.end());//按要求排序
            for (auto& p: person)//遍历每个人
            {
                int nexttime(INF);//维护当前这个人的下次时间点
                if (p.time > time)//当前时间为time的时候这个人在忙
                    nexttime = p.time;
                else//不忙
                {
                    for (int i = 0; i < p.k; i++)//按优先级遍历该人可以处理的主题
                    {
                        Topic& x = topic[p.tid[i]];
                        if (x.table.empty()) continue;//该主题请求已经全部完成
                        if (x.table.front() < nexttime)//该请求无法做
                            nexttime = x.table.front();
                        if (x.table.front() <= time)//该请求可以做
                        {
                            nexttime = time + x.t;//该人的下次时间点为做完这个任务的时间
                            ans = max(ans, nexttime);//维护答案
                            p.st = time;//在做当前任务,那么上次开始处理请求的时间为当前时间
                            x.table.pop();//删掉该主题请求的第一个
                            if (x.table.empty()) N--;//如果该主题请求已经全部完成
                            break;//该人接了一个任务就跳出,不看后面优先级的任务了
                        }
                    }
                    p.time = nexttime;//更改该人的当前时间点
                }
                jumpt = min(jumpt, nexttime);//维护所有人的下个时间点
            }
            time = jumpt;//时间变为所有人的下个时间点
        }
        printf("Scenario %d: All requests are serviced within %d minutes.\n", Scenario++, ans);
    }
    return 0;
}





猜你喜欢

转载自blog.csdn.net/zscdst/article/details/80067934