7-48 银行排队问题之单窗口“夹塞”版
分数 30
作者 DS课程组
单位 浙江大学
排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有1个窗口提供服务,所有顾客按到达时间排成一条长龙。当窗口空闲时,下一位顾客即去该窗口处理事务。此时如果已知第i位顾客与排在后面的第j位顾客是好朋友,并且愿意替朋友办理事务的话,那么第i位顾客的事务处理时间就是自己的事务加朋友的事务所耗时间的总和。在这种情况下,顾客的等待时间就可能被影响。假设所有人到达银行时,若没有空窗口,都会请求排在最前面的朋友帮忙(包括正在窗口接受服务的朋友);当有不止一位朋友请求某位顾客帮忙时,该顾客会根据自己朋友请求的顺序来依次处理事务。试编写程序模拟这种现象,并计算顾客的平均等待时间。
输入格式:
输入的第一行是两个整数:1≤N≤10000,为顾客总数;0≤M≤100,为彼此不相交的朋友圈子个数。若M非0,则此后M行,每行先给出正整数2≤L≤100,代表该圈子里朋友的总数,随后给出该朋友圈里的L位朋友的名字。名字由3个大写英文字母组成,名字间用1个空格分隔。最后N行给出N位顾客的姓名、到达时间T和事务处理时间P(以分钟为单位),之间用1个空格分隔。简单起见,这里假设顾客信息是按照到达时间先后顺序给出的(有并列时间的按照给出顺序排队),并且假设每个事务最多占用窗口服务60分钟(如果超过则按60分钟计算)。
输出格式:
按顾客接受服务的顺序输出顾客名字,每个名字占1行。最后一行输出所有顾客的平均等待时间,保留到小数点后1位。
输入样例:
6 2
3 ANN BOB JOE
2 JIM ZOE
JIM 0 20
BOB 0 15
ANN 0 30
AMY 0 2
ZOE 1 61
JOE 3 10
输出样例:
JIM
ZOE
BOB
ANN
JOE
AMY
75.2
/**
* 看似困难,其实简单;看似简单,其实困难。
* 每个人有一个到达时间,有一个服务时长(服务时长超过60分钟按六十分钟计算,预先处理一
* 下);
* 能够“夹塞”的前提是:在同一个朋友圈里的人,正在服务的这个人还没有结束服务,他的朋友
* 就已经到达,那么可以插队让其帮忙,否则就不行,只能在后面乖乖排队等待,所以这个题用
* 优先队列是不好处理的(至少我现在还没找出优先队列的解决方案),我之前的想法是用优先
* 队列储存信息,但是毫不意外的出现了 WA 。
* 窃以为,想到一种方法,先别急着去编码,看看这种方法能否行得通,否则一切做的都是
* 白用工,我开始编码的时候,我其实知道我的想法是不成熟的,至少存在bug,不过我没有再去
* 深挖它,想着把这个想法用代码实现出来再说,我迫切的需要在以后的日子中改变这种想法,
* 以及思维模式,为什么就这么急着看结果呢,当一种想法能在自己的深思熟虑中“被验证”是完全
* 正确的时候,我们再去编码,也为时不晚呢。
* 谨以此篇来告诫我,望能吸收教训,总结经验,向前进。
*
* total来记录银行事务处理时长(包含空闲的等待时间),wait 记录每个人的等待时间,res为
* 所有人总共等待时间。
*
* 每个人有一个到达时间,有一个服务市场,
* 如果 到达时间 >= total ,直接服务,wait = 0,total = arr + ser;
* 否则到达时间 < total,那么此人就需要等待,wait = total - arr ,total += ser;
*
* 另外用一个 map<string,string> 来记录朋友圈内的信息,假设同一个朋友圈内第一个出现的
* 名字为老大,那么这个朋友圈内的所有人都指向这个老大(包括老大自己);
* 处理信息的时候,从前往后枚举就行了;但得注意看后面的朋友是否满足夹塞情况。
*/
/**
* 看似困难,其实简单;看似简单,其实困难。
* 每个人有一个到达时间,有一个服务时长(服务时长超过60分钟按六十分钟计算,预先处理一
* 下);
* 能够“夹塞”的前提是:在同一个朋友圈里的人,正在服务的这个人还没有结束服务,他的朋友
* 就已经到达,那么可以插队让其帮忙,否则就不行,只能在后面乖乖排队等待,所以这个题用
* 优先队列是不好处理的(至少我现在还没找出优先队列的解决方案),我之前的想法是用优先
* 队列储存信息,但是毫不意外的出现了 WA 。
* 窃以为,想到一种一种方法,先别急着去编码,看看这种方法能否行得通,否则一切做的都是
* 白用工,我开始编码的时候,我其实知道我的想法是不成熟的,至少存在bug,不过我没有再去
* 深挖它,想着把这个想法用代码实现出来再说,我迫切的需要在以后的日子中改变这种想法,
* 以及思维模式,为什么就这么急着看结果呢,当一种想法能在自己的深思熟虑中“被验证”是完全
* 正确的时候,我们再去编码,也为时不晚呢。
* 谨以此篇来告诫我,望能吸收教训,总结经验,向前进。
*
* total来记录银行事务处理时长(包含空闲的等待时间),wait 记录每个人的等待时间,res为
* 所有人总共等待时间。
*
* 每个人有一个到达时间,有一个服务市场,
* 如果 到达时间 >= total ,直接服务,wait = 0,total = arr + ser;
* 否则到达时间 < total,那么此人就需要等待,wait = total - arr ,total += ser;
*
* 另外用一个 map<string,string> 来记录朋友圈内的信息,假设同一个朋友圈内第一个出现的
* 名字为老大,那么这个朋友圈内的所有人都指向这个老大(包括老大自己);
* 处理信息的时候,从前往后枚举就行了;但得注意看后面的朋友是否满足夹塞情况。
*/
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
const int maxn = 10010;
struct Node
{
string name;
int arr,ser;
}a[maxn];
int main()
{
map<string,int> hs;
map<string,string> fre;
int n,m;
cin >> n >> m;
for(int i=0;i<m;++i)
{
string root;
int l;
cin >> l;
for(int j=0;j<l;++j)
{
string name;
cin >> name;
if(j == 0)
root = name;
hs[name] = 0;
fre[name] = root;
}
}
for(int i=0;i<n;++i)
{
string name;
int arr,ser;
cin >> name >> arr >> ser;
ser = min(60,ser);
a[i] = {name,arr,ser};
}
double wait = 0;
double res = 0;
double total = 0;
for(int i=0;i<n;++i)
{
string name = a[i].name;
int arr = a[i].arr;
int ser = a[i].ser;
if(hs[name] == 0)
{
if(arr > total)
total = arr + ser;
else
{
wait = total - arr;
if(wait < 0)
wait = 0;
res += wait;
total += ser;
}
cout << name << endl;
hs[name] = 1;
}
else
continue;
for(int j=i+1;j<n;++j)
{
if(hs[a[j].name] == 0 && fre[name] == fre[a[j].name])
{
if(a[j].arr <= total)
{
wait = total - a[j].arr;
if(wait < 0)
wait = 0;
res += wait;
total += a[j].ser;
hs[a[j].name] = 1;
cout << a[j].name << endl;
}
}
}
}
printf("%.1f\n",res/n);
return 0;
}