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

如有不对,不吝赐教

进入正题:
排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有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

这道题目就是一种特殊的队列,队列的元素是一个个链表,在加入新的元素的时候,要看这个元素是否可以加入到前面元素的链表中,然后就是时间的记录点,详情可以看待会的测试结果。

给出代码:

#include<stdio.h>
#include<string.h>
#include<malloc.h>

struct ClientHead{
short key;               //表示这是哪个朋友圈
struct Client *head;
struct Client *tail;      //顾客链表的头尾
};       //构成链表数组

struct Client{
short rest;             //从当前计时 解决该顾客还要多长时间
char name[4];           //当前顾客姓名
struct Client *next;
};

struct Arrive{
char name[4];
short T;     //到达时间
short P;     //事务处理时间
};

short root[16276];    //朋友圈
short first[16276];   //某个朋友圈在队列里的第一个位置
short tail=0;             //当前处理顾客队列的尾(最后一个顾客)

short Hash(char *name);
void Insert(struct ClientHead *p[],struct Arrive *arrive);

int main(void)
{
    struct Client *cur;       //表示当前正在处理的顾客
    short N,M,L;        //顾客总数 朋友圈数 朋友圈的朋友人数
    short i,j;
    short key;          //映射到Hash表上的关键值
    int timeTable,allTime;     //当前时间  //当前顾客花费的总时间
    char name[4];
    fscanf(stdin,"%hd %hd",&N,&M);
    struct Arrive *arrive[N];  //顾客到达的顺序
    struct ClientHead *execute[N];       //顾客的处理顺序
    short head=0;               //当前处理顾客队列的头
    short wait=-1;              //当前正在等待的顾客人数
    double average;            //顾客等待平均时间
    timeTable=allTime=0;        //初始化时间

    for(i=0;i<N;i++){
      execute[i]=(struct ClientHead *)malloc(sizeof(struct ClientHead));
      execute[i]->head=NULL;
      execute[i]->tail=NULL;
      execute[i]->key=-1;
      arrive[i]=(struct Arrive *)malloc(sizeof(struct Arrive));
    }         //初始化链表数组

    for(i=0;i<16276;i++)
      first[i]=-1;       //初始化所有顾客的位置 都不在队列中

    for(i=0;i<M;i++){
      fscanf(stdin,"%hd",&L);
      for(j=0;j<L;j++){
        key=0;
        fscanf(stdin,"%s",name);
        key=Hash(name);
        if(!j)
          head=key;
        root[key]=head;       //形成以第一个为中心的圈子
      }
    }  //读入朋友圈

    for(i=0,j=0;i<N;i++){       //读入顾客到达的顺序
      fscanf(stdin,"%s %hd %hd",arrive[i]->name,&arrive[i]->T,&arrive[i]->P);
      if(arrive[i]->P>60)
        arrive[i]->P=60;
    }

    i=0;
    head=0;
    while(i<N){
      if(-1==wait){
        Insert(execute,arrive[i]);
        cur=execute[head]->head;
        timeTable=arrive[i]->T;
        key=Hash(arrive[i]->name);
        first[key]=head;
        wait++;
        i++;
      }               //没人等待的时间段

      while(cur&&i<N&&cur->rest+timeTable>=arrive[i]->T&&-1!=wait){
        while(i<N&&timeTable==arrive[i]->T){
          Insert(execute,arrive[i]);
          wait++;
          i++;
        }
        if(i>=N||cur->rest+timeTable<arrive[i]->T)
          break;
        allTime+=wait*(arrive[i]->T-timeTable);
        Insert(execute,arrive[i]);
        wait++;
        cur->rest-=(arrive[i]->T-timeTable);   //更改该顾客的事务时间
        timeTable=arrive[i]->T;         //将时间快进到顾客来的时刻
        i++;                            //指向下一个顾客
      }                //一项任务完成之前来顾客

      while(cur&&i<N&&cur->rest+timeTable<arrive[i]->T&&-1!=wait){
        allTime+=wait*cur->rest;
        timeTable+=cur->rest;
        wait--;
        printf("%s\n",cur->name);
        cur=cur->next;
      }   //一项任务完成之后才来顾客
      if(!cur){
        first[execute[head]->key]=-1;
        head++;
        cur=execute[head]->head;
      }
    }

    while(head<tail){
      while(cur){
        printf("%s\n",cur->name);
        allTime+=wait*cur->rest;
        wait--;
        cur=cur->next;
      }
      head++;
      if(head<tail)
        cur=execute[head]->head;
    }

    if(!N)
      average=0;
    else
      average=1.0*allTime/N;

    printf("%.1lf",average);

    for(i=0;i<N;i++){
      free(arrive[i]);
      arrive[i]=NULL;
    }

    for(i=0;i<tail;i++){
      cur=execute[i]->head->next;
      while(cur){
        execute[i]->head->next=cur->next;
        free(cur);
        cur=NULL;
        cur=execute[i]->head->next;
      }
      free(execute[i]->head);
      execute[i]->head=NULL;
      free(execute[i]);
      execute[i]=NULL;
    }

    return 0;
}

short Hash(char *name)
{
    short key;

    key=(name[0]-'A')*25*25+(name[1]-'A')*25+(name[2]-'A');

    return key;
}

void Insert(struct ClientHead *p[],struct Arrive *arrive)
{
    struct Client *newOne;
    short key;
    short head;
    newOne=(struct Client *)malloc(sizeof(struct Client));
    strcpy(newOne->name,arrive->name);
    newOne->rest=arrive->P;
    newOne->next=NULL;
    key=Hash(arrive->name);
    head=root[key];

    if(-1==first[head]){
      p[tail]->key=head;   //标记该朋友圈
      p[tail]->head=newOne;
      p[tail]->tail=p[tail]->head;
      first[head]=tail;
      tail++;
    }
    else{
      head=first[head];
      p[head]->tail->next=newOne;
      p[head]->tail=p[head]->tail->next;
    }

    return ;
}

测试结果:
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值