算法竞赛入门经典 习题5-13

UVa822

Queue and A

客户中心的员工需要对不同主题的请求进行处理。每个员工根据其专业程度的不同,预先对不同主题的处理优先级进行了排序。当员工空闲时,其会根据处理优先级提取请求进行。当多个员工提取了同一请求时,该请求会被分配给最早开始处理上一个请求的员工;如果出现多个员工最早开始处理上一个请求的时间一样,则该请求会被分配给输入靠前的员工。

一道复杂的模拟型题目,最简单的方式是通过时间进行模拟,即在每一个可以调度的时刻,根据冲突处理规则进行调度。

这一道题写了一礼拜,问题在于题目描述存在歧义,大概可以存在以下三种解释,均可以AC:

  1. 空闲的员工先从优先级高的队列中提取请求,然后进行冲突处理,需要重新提取请求的员工重复上述过程,直到没有员工空闲或者没有请求挂起,这是一个并行的过程,且不同的请求上的冲突是独立的
  2. 空闲的员工先从优先级最高的队列中提取请求,然后进行冲突处理,需要重新提取请求的员工从再第2优先级的队列中提取请求,冲突处理后需要重新提取请求的员工从再第3优先级的队列中提取请求,直到没有员工空闲或者没有请求挂起,这也是一个并行的过程,和上一种的区别在于重新提取请求时不再从最高优先级开始,具体实现可以参考这篇题解
  3. 《算法竞赛入门经典 习题与解答》上的解释,也可以参考这篇题解。不同于上面两种解释方式,不同请求上的冲突是不独立的,也就是说在不同的请求上发生冲突时,只能根据冲突处理规则将一个请求分配给一个员工,其余员工都需要重新提取请求,这本质上是一个串行的过程,因此可以根据冲突处理规则对员工进行排序,然后依次让每个员工提取请求

下面这个例子可以说明第一种解释和第二种解释的的区别,AB两个员工的优先级列表如下所示,当需要分配请求2的时候,按照第一种解释,在第一轮提取中AB都会提取到该请求,然后按照冲突处理规则处理即可;而按照第二种解释,第一轮提取后AB都不会提取到请求,而第二轮后B会提取到该请求。

2
A: {4 3 1 2}
B: {1 2 3}

下面这个例子可以说明第一种解释和第三种解释的的区别,ABC三个员工的优先级列表如下所示,当需要分配请求712的时候,AB都会提取到请求7,而只有C会提取到请求12。在第一种解释中,请求7最终会分配给AB需要重新提取请求,请求12最终会分配给C;而在第三种解释中,BC都需要重新提取请求,最终请求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
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值