银行排队问题之单窗口“夹塞”版--PTA数据与结构

7-4 银行排队问题之单窗口“夹塞”版(30 分)

排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有1个窗口提供服务,所有顾客按到达时间排成一条长龙。当窗口空闲时,下一位顾客即去该窗口处理事务。此时如果已知第i位顾客与排在后面的第j位顾客是好朋友,并且愿意替朋友办理事务的话,那么第i位顾客的事务处理时间就是自己的事务加朋友的事务所耗时间的总和。在这种情况下,顾客的等待时间就可能被影响。假设所有人到达银行时,若没有空窗口,都会请求排在最前面的朋友帮忙(包括正在窗口接受服务的朋友);当有不止一位朋友请求某位顾客帮忙时,该顾客会根据自己朋友请求的顺序来依次处理事务。试编写程序模拟这种现象,并计算顾客的平均等待时间。

输入格式:

输入的第一行是两个整数:1N10000,为顾客总数;0M100,为彼此不相交的朋友圈子个数。若M非0,则此后M行,每行先给出正整数2L100,代表该圈子里朋友的总数,随后给出该朋友圈里的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
        这个题目实质就是一个简单的模拟,我们首先需要考虑一下我们应该怎么储存朋友之间的关系,然后通过姓名迅速判断是否是朋友,我们这里就是用的map来一一对应,后面将每个人放到队列中,我们每次都从队列的开头去除一个元素,然后往后判断,如果在他办理业务的时间之中,会有他的朋友来到银行,那么我们就把这个朋友标记一下,后面再从队列取出这个人时,他已经是办理过的了,所以就不考虑了,然后这个插队的人的等待时间就是正在办理业务的朋友手中需要办理的业务时间减去他来的时间。那么这里的last就是从开始办理业务到现在所持续的时间,先要计算等待的时间就等于持续的时间减去这个人到达的时间。如果窗口出现了空闲的时间,那么我们这里的last就需要重新计数了,因为我们不能加上中间这段空闲的时间,所以这个last就被重新定义为空闲之后的第一个人办理完业务的时间。
(答案仅供参考)


#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cstdlib>
#define INF 0x3f3f3f3f

using namespace std;
const int MAXN = 10100;
struct Peo
{
    char name[5];
    int s;
    int e;
    int pos;
} peo[MAXN];
int N,M;
vector<string> fir[110];
map<string,int> group;
char name[5];
queue<Peo> que;//表示排的队伍

int main()
{
    scanf("%d%d",&N,&M);
    int num;
    for(int i =0 ; i < M; i ++)
    {
        scanf("%d",&num);
        for(int j =0 ; j < num; j ++)
        {
            scanf("%s",name);
            fir[i].push_back(name);
            group[name] = i;
        }
    }
    for(int i =0 ; i < N; i ++)
    {
        scanf("%s%d%d",&peo[i].name,&peo[i].s,&peo[i].e);
        peo[i].e = peo[i].e>60?60:peo[i].e;
        peo[i].pos = i;
        que.push(peo[i]);
    }
    //首先是第一个到达的进队
    int last = 0;//表示业务持续的时间
    int ans = 0;
    bool flag[MAXN] = {false};//表示是否在队伍中
    while(!que.empty())
    {
        Peo temp = que.front();
        que.pop();
        if(!flag[temp.pos])
        {
            flag[temp.pos] = true;
            if(temp.s <= last)//只有前面有人的时候,加上等待的时间
            {
                ans += last - temp.s;
                last +=  temp.e;
            }
            else//如果是前面没有人的话,那么这里持续的时间就应该从这个人开始重新计算。
            {
                ans += 0 ;last = temp.s+temp.e;
            }
            printf("%s\n",temp.name);
            for(int i =temp.pos+1 ; i < N; i ++) //
            {
                if(peo[i].s > last)//表示队伍中的人已经离开!
                    break;
                if(temp.name != peo[i].name &&!flag[i]&&group.count(temp.name)&&group.count(peo[i].name)&&group[temp.name] == group[peo[i].name])//如果是找到了前面的朋友
                {
                    flag[i] = true;
                    printf("%s\n",peo[i].name);
                    ans += last - peo[i].s;//等待时间为到达时间到朋友办完业务的时间差
                    last += peo[i].e;
                }
            }
        }
    }
    printf("%.1f",1.0*ans/N);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值