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

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

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

输入的第一行是两个整数:1≤N≤10000,为顾客总数;0≤M≤1000,为彼此不相交的朋友圈子个数。若M非0,则此后M行,每行先给出正整数2≤L≤100,代表该圈子里朋友的总数,随后给出该朋友圈里的L位朋友的名字。名字由3个大写英文字母组成,名字间用1个空格分隔。最后N行给出N位顾客的姓名、到达时间TTT和事务处理时间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

思路
我是用了一个{Right*,Next*}的链表来描述这个排队的情况。关于朋友圈通讯录的表示方法,我用了链表,方法不够简洁,其实用数组就好了,每一个朋友圈定义一个编号,对于任意两个人来说,只要他们所属的朋友圈是同一个,那他们就可以互相插队。

点击访问 PTA-测验

#include <stdio.h>
#include<stdlib.h>
/* 评测结果 时间  结果  得分  题目  编译器     用时(ms)  内存(MB)  用户
2016-08-31 11:38    答案正确    30  5-48    g++     371     63  569985011
测试点结果 测试点   结果  得分/满分   用时(ms)  内存(MB)
测试点1    答案正确    17/17   2   1
测试点2    答案正确    3/3     2   1
测试点3    答案正确    3/3     2   1
测试点4    答案正确    2/2     2   1
测试点5    答案正确    1/1     2   1
测试点6    答案正确    1/1     2   1
测试点7    答案正确    3/3     371     63
查看代码*/
typedef struct name {
    int X,Y,Z;
}*Name;
typedef struct friends *Friend;
struct friends {
    Name Who;
    Friend Next;//表示下一位朋友
};
typedef struct node *Node;
struct node {
    Name Who;
    int Start;//统计他开始的时间,
    int Reached;//他本人到达的时间记为负
    int Lenth;//他本人需要办理的工作时间长度
    Node Right;//表示他准备帮忙完成的朋友
    Node Next;//对列中的下一位
};
Friend List[26][26][26]={0}; //通讯录,保存每个人的朋友信息
int sum=0;
void ReadList();
Name scanName();
Node Insert(Node,Name,int,int,int);
void CutInLine(Node,int);
void fun(Node h) {
    if(h) {
        printf("%c%c%c\n",h->Who->X+'A',h->Who->Y+'A',h->Who->Z+'A');
//      if(h->Start>h->Reached)//如果抵达时间晚于开始时间,那么不用排队
            sum+=h->Start-h->Reached;
//  printf("%d,%d\n",h->Reached,h->Start);
        fun(h->Right);
        fun(h->Next);
    }
}
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0; i<m; i++)ReadList();
    Node Head=NULL;
    int start=0;
    for(int i=0; i<n; i++) {
        Name temp=scanName();
        int reached,lenth;
        scanf("%d%d",&reached,&lenth);
        if(lenth>60)lenth=60;
        while(Head&&Head->Lenth+Head->Start<reached) {//如果这次进来的新人来时队伍第一人已经离开了,那就结算
            for(Node h=Head; h; h=h->Right) {
                printf("%c%c%c\n",h->Who->X+'A',h->Who->Y+'A',h->Who->Z+'A');
//              if(h->Start>h->Reached)
                    sum+=h->Start-h->Reached;
            }
//      start+=Head->Start+Head->Lenth;
            Head=Head->Next;//删除已完成服务的客户

        }if(Head)//如果队列为空,那么他什么时候来就什么时候办理
        Head=Insert(Head,temp,reached,0,lenth);//否则就从队列第一人开始累加
        else Head=Insert(NULL,temp,reached,reached,lenth);
    }
    fun(Head);//停止接客后结算等待
    printf("%.1f",sum*1.0/n);



    return 0;
}


Node Insert(Node h,Name who, int reached,int start, int lenth) {
    if(!h) {
        Node temp=(Node)malloc(sizeof(struct node));
        temp->Lenth=lenth;
        temp->Next=NULL;
        temp->Right=NULL;
        temp->Start=start;
        temp->Who=who;
        temp->Reached=reached;
        return temp;
    }

    Friend py=List[who->X][who->Y][who->Z];
    while(py)if(py->Who->X==h->Who->X&&py->Who->Y==h->Who->Y&&py->Who->Z==h->Who->Z)break;
        else py=py->Next;

    if(py) { //如果新人正好和当前这个人认识,那么插队。
        Node temp=h;//站到这一排的最边上等着。
        while(temp->Right)temp=temp->Right;
        temp->Right=Insert(NULL,who,reached,h->Start+h->Lenth,lenth);
        h->Lenth+=lenth;
        CutInLine(h->Next,lenth);
    } else { //既然不认识,那就找下一个团伙
        h->Next=Insert(h->Next,who,reached,h->Start+h->Lenth,lenth);
    }



    return h;
}

void CutInLine(Node h,int lenth) {//被插队的人全部多等lenth分钟
    if(!h)return;
    h->Start+=lenth;
    CutInLine(h->Right,lenth);
    CutInLine(h->Next,lenth);
}

Name scanName() {
    getchar();
    char x,y,z;
    scanf("%c%c%c",&x,&y,&z);
    Name temp=(Name)malloc(sizeof(struct name));
    temp->X=x-'A';
    temp->Y=y-'A';
    temp->Z=z-'A';
    return temp;
}
void ReadList() {
    int num;
    scanf("%d",&num);
    Friend stack=(Friend)malloc(sizeof(struct friends)*num);
    for(int i=0; i<num; i++) {
        stack[i].Who=scanName();
//      printf("{%c,%c,%c}",stack[i].Who.X+'A',stack[i].Who.Y+'A',stack[i].Who->Z+'A');
    }
    for(int i=0; i<num; i++) {
        for(int j=0; j<num; j++) {
//          if(i==j)continue;
            Friend temp=(Friend)malloc(sizeof(struct friends));
            temp->Who=(Name)malloc(sizeof(struct name));
            temp->Who->X=stack[j].Who->X;
            temp->Who->Y=stack[j].Who->Y;
            temp->Who->Z=stack[j].Who->Z;
            temp->Next=List[stack[i].Who->X][stack[i].Who->Y][stack[i].Who->Z];
            List[stack[i].Who->X][stack[i].Who->Y][stack[i].Who->Z]=temp;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值