UVa822
客户中心的员工需要对不同主题的请求进行处理。每个员工根据其专业程度的不同,预先对不同主题的处理优先级进行了排序。当员工空闲时,其会根据处理优先级提取请求进行。当多个员工提取了同一请求时,该请求会被分配给最早开始处理上一个请求的员工;如果出现多个员工最早开始处理上一个请求的时间一样,则该请求会被分配给输入靠前的员工。
一道复杂的模拟型题目,最简单的方式是通过时间进行模拟,即在每一个可以调度的时刻,根据冲突处理规则进行调度。
这一道题写了一礼拜,问题在于题目描述存在歧义,大概可以存在以下三种解释,均可以AC:
- 空闲的员工先从优先级高的队列中提取请求,然后进行冲突处理,需要重新提取请求的员工重复上述过程,直到没有员工空闲或者没有请求挂起,这是一个并行的过程,且不同的请求上的冲突是独立的
- 空闲的员工先从优先级最高的队列中提取请求,然后进行冲突处理,需要重新提取请求的员工从再第
2
优先级的队列中提取请求,冲突处理后需要重新提取请求的员工从再第3
优先级的队列中提取请求,直到没有员工空闲或者没有请求挂起,这也是一个并行的过程,和上一种的区别在于重新提取请求时不再从最高优先级开始,具体实现可以参考这篇题解 - 《算法竞赛入门经典 习题与解答》上的解释,也可以参考这篇题解。不同于上面两种解释方式,不同请求上的冲突是不独立的,也就是说在不同的请求上发生冲突时,只能根据冲突处理规则将一个请求分配给一个员工,其余员工都需要重新提取请求,这本质上是一个串行的过程,因此可以根据冲突处理规则对员工进行排序,然后依次让每个员工提取请求
下面这个例子可以说明第一种解释和第二种解释的的区别,A
和B
两个员工的优先级列表如下所示,当需要分配请求2
的时候,按照第一种解释,在第一轮提取中A
和B
都会提取到该请求,然后按照冲突处理规则处理即可;而按照第二种解释,第一轮提取后A
和B
都不会提取到请求,而第二轮后B
会提取到该请求。
2
A: {4 3 1 2}
B: {1 2 3}
下面这个例子可以说明第一种解释和第三种解释的的区别,A
、B
和C
三个员工的优先级列表如下所示,当需要分配请求7
和12
的时候,A
和B
都会提取到请求7
,而只有C
会提取到请求12
。在第一种解释中,请求7
最终会分配给A
,B
需要重新提取请求,请求12
最终会分配给C
;而在第三种解释中,B
和C
都需要重新提取请求,最终请求12
会分配给B
。
7 12
A: {7 12}
B: {7 12}
C: {1 12}
最终AC的代码是按照第一种解释方式编写的。
#include <iostream>
#include <algorithm>
#include <climits>
#include <map>
#include <set>
#include <vector>
using namespace std;
struct Topic
{
int identifier;
int number;
int ElapsedTime;
int ServiceTime;
int SuccessiveTime;
};
istream& operator >> (istream &is, Topic &topic)
{
is >> topic.identifier >> topic.number >> topic.ElapsedTime
>> topic.ServiceTime >> topic.SuccessiveTime;
return is;
}
struct Staff
{
int identifier;
vector<int> topics;
int ReadyTime;
int LastScheduled;
};
istream &operator >> (istream &is, Staff &staff)
{
int n;
is >> staff.identifier >> n;
staff.topics.resize(n);
for (int i = 0; i < n; i++)
{
is >> staff.topics[i];
}
staff.ReadyTime = 0;
staff.LastScheduled = 0;
return is;
}
map<int, vector<size_t>> SelectRequest(map<int, Topic> &RequestQueue, vector<Staff> &staffs, int current)
{
map<int, vector<size_t>> selected;
for (size_t i = 0; i < staffs.size(); i++)
{
if (staffs[i].ReadyTime <= current) {
for (int TopicID : staffs[i].topics)
{
auto iter = RequestQueue.find(TopicID);
if (iter != RequestQueue.end()) {
if (RequestQueue[iter->first].number != 0 && iter->second.ElapsedTime <= current) {
selected[TopicID].push_back(i);
break;
}
}
}
}
}
return selected;
}
bool SolveConflict(map<int, Topic> &RequestQueue, vector<Staff> &staffs, int current,
map<int, vector<size_t>> &selected, set<int> &SchedulingTime)
{
bool conflict = false;
for (auto iter = selected.begin(); iter != selected.end(); iter++)
{
vector<size_t> &ConflictStaffIndex = iter->second;
int LastScheduled = staffs[ConflictStaffIndex.front()].LastScheduled;
size_t index = 0;
if (ConflictStaffIndex.size() > 1) {
conflict = true;
for (size_t i = 1; i < ConflictStaffIndex.size(); i++)
{
if (staffs[ConflictStaffIndex[i]].LastScheduled < LastScheduled) {
LastScheduled = staffs[ConflictStaffIndex[i]].LastScheduled;
index = i;
}
}
}
Topic &topic = RequestQueue[iter->first];
Staff &staff = staffs[ConflictStaffIndex[index]];
staff.LastScheduled = current;
staff.ReadyTime = current + RequestQueue[iter->first].ServiceTime;
SchedulingTime.insert(staff.ReadyTime);
if (--topic.number != 0) {
topic.ElapsedTime += topic.SuccessiveTime;
}
else {
RequestQueue.erase(iter->first);
}
}
return conflict;
}
int GetNextRequestTime(const map<int, Topic> &RequestQueue, int current)
{
int time = INT_MAX;
for (auto iter = RequestQueue.begin(); iter != RequestQueue.end(); iter++)
{
if (current < iter->second.ElapsedTime && iter->second.ElapsedTime < time) {
time = iter->second.ElapsedTime;
}
}
return time;
}
int ServiceTime(map<int, Topic> &RequestQueue, vector<Staff> &staffs)
{
set<int> SchedulingTime;
int current = 0;
SchedulingTime.insert(current);
while (!SchedulingTime.empty()) {
current = *SchedulingTime.begin();
SchedulingTime.erase(SchedulingTime.begin());
bool conflict = true;
while (conflict) {
map<int, vector<size_t>> selected = SelectRequest(RequestQueue, staffs, current);
if (selected.empty()) break;
conflict = SolveConflict(RequestQueue, staffs, current, selected, SchedulingTime);
}
if (RequestQueue.empty()) break;
int NextRequestTime = GetNextRequestTime(RequestQueue, current);
if (NextRequestTime != INT_MAX) {
SchedulingTime.insert(NextRequestTime);
}
}
return *SchedulingTime.rbegin();
}
int main()
{
int request, personnel, scenario = 1;
while (cin >> request) {
if (request == 0) break;
map<int, Topic> RequestQueue;
vector<Staff> staffs;
for (int i = 0; i < request; i++)
{
Topic topic;
cin >> topic;
RequestQueue[topic.identifier] = topic;
}
cin >> personnel;
for (int i = 0; i < personnel; i++)
{
staffs.push_back(Staff());
cin >> staffs.back();
}
sort(staffs.begin(), staffs.end(), [](const Staff &a, const Staff &b)
{
return a.identifier < b.identifier;
});
cout << "Scenario " << scenario++ << ": All requests are serviced within "
<< ServiceTime(RequestQueue, staffs) << " minutes." << endl;
}
return 0;
}
/*
3
128 20 0 5 10
134 25 5 6 7
153 30 10 4 5
4
10 2 128 134
11 1 134
12 2 128 153
13 1 153
0
*/