题意:你的任务是模拟一个客户中心运作情况。客服请求共有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;
}