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

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

题目描述:

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

解体思路:

本题的主要难点是 “朋友”的存储问题,怎样把一个人的朋友坐标志,刚开始想用树,一个人的朋友在一棵树上,但是比较麻烦,因为这一群人是朋友,树的孩子之间又有联系,所以行不通。想到用 来存储朋友,不同的朋友的值相同就可以标志。 再就是队列的操作,可能是队中的人出队,就很难操作(因为队列只能出对头或队尾(双向队列)),可以设置一个visited[]数组标志。关于等待时间在代码中有描述。

答案:

#include <bits/stdc++.h>
#define MaxNum 10010
using namespace std;

struct peo
{
    string name;
    int Start_Time;
    int End_Time;
    int Pos;
}People[MaxNum];//顾客信息

queue<peo>Customer;     //记录排队的顾客
map<string,int>Friends; //朋友集
bool visited[MaxNum] = {false}; //记录顾客的状态

int main()
{
    int N,M;
    scanf("%d%d",&N,&M);
    int i,j;
    for(i = 0;i < M; ++i)
    {
        int num;
        scanf("%d",&num);
        for(j = 0;i < num; ++j)
        {
            string name;
            scanf("%s",&name);
            Friends[name] = i;
        }
    }

    for(i = 0;i < N; ++i)
    {
        scanf("%s%d%d",&People[i].name,&People[i].Start_Time,&People[i].End_Time);
        if(People[i].End_Time > 60)
        People[i].End_Time = 60;
        People[i].Pos = i;
        Customer.push(People[i]);
    }

    int last = 0;
    int result = 0;

    while(!Customer.empty())
    {
        peo temp = Customer.front();
        Customer.pop();
        if(!visited[temp.Pos]) //没有办理过业务才进行
        {
            printf("%s\n",temp.name);
            visited[temp.Pos] = true;
            if(temp.Start_Time <= last) //如果一个人开始的时间小于最后一个人办完的时间,他就要等待
            {
                result += last-temp.Start_Time;  //一个人他前面的最后一个人办完需要的时间 - 这个人来的时间 = 他要等待的时间
                last += temp.End_Time; //更新办完当前业务需要的时间 (加上来这个人办业务需要的时间)
            }
            else
            {
                last = temp.End_Time+temp.Start_Time; 
                //如果一个人来的时候他前面的人都办完了,就不需要等待了,所以result+=0,不需要更新,只要更新办完当前事务的时间就行
            }
            
            for(i = temp.Pos+1 ; i < N ; ++i)  //找朋友
            {
                if(People[i].Start_Time > last)
                    break;    //该情况不需要找朋友,直接办就行了,因为没有等待时间
                if(temp.name != People[i].name && !visited[i] && Friends.count(temp.name) && Friends.count(People[i].name) && Friends[temp.name] == Friends[People[i].name])
            {
                //如果对于一个人有朋友的话,就可以随着朋友直接输出
                visited[i] = true;
                printf("%s\n",People[i].name);
                result += last - People[i].Start_Time;  //同上,一个人他前面的最后一个人办完需要的时间 - 这个人来的时间 = 他要等待的时间
                last += People[i].End_Time; //同上,更新办完当前业务需要的时间 (加上来这个人办业务需要的时间)
            }

            }
        }
    }
printf("%1f\n",1.0*result/N);
    return 0;
}

可能是编译器的问题还是其他问题,在运行中可能出现小错误,PTA上还没过,正在改代码。不要直接复制代码。但思路是对的,可以根据思路自行调试改正代码。

谢谢采纳!

银行排队问题通常是一个经典的计算机科学问题,用于演示算法设计中的并发控制和同步机制。在这个场景下,假设有一个单窗口服务,同时有若干名顾客排队等候。当一个窗口空闲时,如果有多名顾客等待,系统如何保证公平地让每个顾客都有机会办理业务而不发生插队现象。 "单窗口夹塞"指的是如果有新来的顾客想要插入队伍中,系统需要判断是否允许插入,避免形成不公平的情况。一种常见的解决方案是采用先进先出(FIFO,First In First Out)原则。我们可以使用C语言创建一个简单的模拟: 1. 定义一个数据结构,比如`struct Customer`,包含顾客的ID和到达时间。 2. 创建一个队列(如`queue_t`),用于存储等待的顾客。可以使用`stdlib.h`中的`#include <queue>`来使用`std::queue`或者自定义队列实现。 3. 当窗口空闲时,检查队列头部的顾客是否已经超过了他们应该等待的时间(即当前时间减去他们到达时间)。如果未超过,让他们进入服务;否则,拒绝新来的顾客插队,保持顺序。 4. 使用互斥量(mutex)来保护对队列的操作,防止多个线程同时修改。 示例代码(简化): ```c #include <stdio.h> #include <stdlib.h> #include <time.h> typedef struct { int id; time_t arrival_time; } Customer; // 简化的队列实现 typedef struct { Customer* front; Customer* rear; } Queue; Queue queue_init() { ... } void queue_push(Queue*, Customer*) { ... } Customer* queue_pop(Queue*) { ... } int main() { Queue window_queue; clock_t start_time; while (true) { // 模拟服务开始 if (queue_is_empty(&window_queue)) { // 获取当前时间和新顾客信息 start_time = clock(); Customer new_customer = generate_random_customer(); // 判断是否允许夹塞 if (!can_insert(&window_queue, new_customer.arrival_time, start_time)) { printf("新顾客不允许夹塞,继续排队...\n"); } else { queue_push(&window_queue, &new_customer); printf("顾客 %d 入队...\n", new_customer.id); } } else { // 服务处理 Customer* customer = queue_pop(&window_queue); process(customer); free(customer); // 不妨清理资源 } } return 0; } // 插入判断函数 bool can_insert(Queue* queue, time_t arrival_time, clock_t current_time) { Customer* front = queue->front; return current_time - arrival_time <= get_wait_time(front->arrival_time); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值