习题8.3 银行排队问题之单窗口“夹塞”版 (30point(s))
排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有1个窗口提供服务,所有顾客按到达时间排成一条长龙。当窗口空闲时,下一位顾客即去该窗口处理事务。此时如果已知第i位顾客与排在后面的第j位顾客是好朋友,并且愿意替朋友办理事务的话,那么第i位顾客的事务处理时间就是自己的事务加朋友的事务所耗时间的总和。在这种情况下,顾客的等待时间就可能被影响。假设所有人到达银行时,若没有空窗口,都会请求排在最前面的朋友帮忙(包括正在窗口接受服务的朋友);当有不止一位朋友请求某位顾客帮忙时,该顾客会根据自己朋友请求的顺序来依次处理事务。试编写程序模拟这种现象,并计算顾客的平均等待时间。
Example:
#include <iostream>
#include <cstdio>
#include <vector>
#include <unordered_map>
#include <list>
using namespace std;
struct Customer {
string name;
int T;
int P;
int id;
};
unordered_map<string, int> circle;
vector<Customer> customer;
vector<int> wait;
list<Customer*> queue;
int main()
{
int N, M;
cin >> N >> M;
circle.reserve(N);
for (int i = 0; i < M; i++) {
string name;
int L;
cin >> L;
for(int j = 0; j < L; j++) {
cin >> name;
circle.insert(make_pair(name, i+1));
}
}
customer.resize(N);
wait.resize(N);
for(int i = 0; i < N; i++) {
cin >> customer[i].name >> customer[i].T >> customer[i].P;
customer[i].id = circle[customer[i].name];
queue.push_back(&customer[i]);
}
int last_finish = 0;
for(int i = 0; i < N;) {
Customer *c = queue.front();
int id = c->id;
if(last_finish < c->T) last_finish = c->T;
if(id == 0) {
wait[i++] = last_finish - c->T;
last_finish += min(c->P, 60);
cout << c->name << endl;
queue.pop_front();
} else {
for(auto x = queue.begin(); x != queue.end(); ++x) {
if((*x)->T > last_finish) break;
if((*x)->id != id) continue;
wait[i++] = last_finish - (*x)->T;
last_finish += min((*x)->P, 60);
cout << (*x)->name << endl;
x = queue.erase(x);
--x;
}
}
}
double sum = 0;
for(auto &x : wait) sum += x;
printf("%.1f\n", sum/N);
return 0;
}
思路:
使用最近一个的结束时间,检查后面同个圈子的朋友是否有到达时间在最近结束时间内,如果是就继续处理;
如果没有圈子的按照普通队头普通出队处理。