爆刷PAT(甲级)——之【1014】 Waiting in Line (30)(30 分)——队列的使用

题意: 银行柜台有N个,每个柜台可以独立干活排队。

    每个柜台后面黄线内可以排队,可以排M个人。如果人满了,要么去别的队伍,要么去旁边等着。
    一共有K个客户。每个客户自行去排队,客户排队的时候,会选择最快的队伍!每个客户需要Ti的时间处理业务。队伍前面的客户业务办完了,后面的客户办。
    银行早上8点开始上班,下午17点关门。
    输入Q此询问,每次输出特定的客户,什么时候能够完成业务滚出银行,如果这个人在银行下班了还没有来得及被受理业务,就输出Sorry。

难点:没想到吧,这就是一道模拟题!然鹅难以下手,因为题目冗长的恶心,以及柜台各自成队伍。写了好几次,样例都过不了,本来用的是priority_queue,最后发现是用普通的队列即可。

后来参照了柳神的代码,好短啊。。。为什么我写的又臭又长。。。

没有细看柳神的代码,再次重写本题代码。

遇见的几个剧毒的坑:

1、客户选哪个队伍,并不是“上帝视角”!他们是不知道别人的业务要办理多久的!所以,客户选人,只会看哪条队伍可以哦排队了,就去哪条队伍

2、柜台受理的工作时间定义:柜台在17:00分之前,都是受理的,不论你的业务多久!如果你的在16:59分办理60分钟的业务,柜台也会兢兢业业的帮你完成!但是在大于等于17:00分之后,就不受理了

3、题目要求输出的是客户的业务完成时间,而不是业务受理时间。比如刚刚的例子,16:59分受理60分钟的业务,那么这个客户就输出17:59分,而不是16:59.

4、这个最大的毒瘤。。。WA了半天,找不到错误,逻辑没毛病,算法应该OK,为什么WA。一个样例过不了,多半是特例。两天以后,我才发现,测试数据里黄线内可容纳的人数,tm可以为0.。。。。为什么没有博客发现这一点。。心好累,此题有毒,你黄线内容纳的人数为0,那不是表示银行不干活了吗!通过这个测试点1的办法就是,把输入m为0特判一下,改成1即可。这也再次体现的我算法的差劲,柳神的代码都不需要特判的。。。

Code:

本人思路:

每个柜台都有一个队列;队首的客户完成业务的时间——用来给模拟客户选择,哪只柜台的队伍先空出来;当前队末客户业务完成的时间,用来计算输出的结果。

先把所有人都装入到黄线内,采用轮询的方式。同时计算维护柜台的参数,并计算这些人的时间答案。

再模拟剩下的客户排队的情况,算出剩下人的答案。

在输入的部分,特判了m==0的情况。

 

程序代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 1009
#define INF 0x3f3f3f3f
#define loop(x,y,z) for(x=y;x<z;x++)

int n,m,k,q;//柜台、线内、顾客、查询
int cost[inf];//顾客消耗时间
int ans[inf];//顾客完成时间
int maxTime=9*60;//最多等待时间9个小时
bool book[inf];//标记顾客来的来不及开始
struct Node
{
    queue<int>q;
    int time_first;//队首人什么时候出来,用于黄线外人选择
    int time_end;//队尾这个人什么时候出来,用于记录终解
    Node()
    {
        while(!q.empty())q.pop();
        time_first=time_end=0;
    }
}counter[22];//柜台

void Solve()//客户自0始
{
    memset(book,0,sizeof book);
    int i,j,index=0;
    bool tag=true;//循环结束标记
    while(index<k&&tag)//先把黄线内装满
    {
        tag=false;
        loop(j,0,n)
            if(counter[j].q.size()<m)//装入此人,并计算此人出来的时间
            {
                counter[j].q.push(index);
                if(counter[j].time_end>=maxTime)book[index]=true;//判断前面的人完成的时候,是不是关门了
                counter[j].time_end+=cost[index];//累加,计算自己什么时候出来
                ans[index]=counter[j].time_end;//保存结果,以备输出
                //printf("debug: %d\n",ans[index]);
                index++;
                tag=true;
            }
    }
    loop(i,0,n)//柜台第一个人出来的时间
    {
        int t=counter[i].q.front();
        counter[i].time_first=cost[t];//队首人走的时间
    }
    //开始计算每个人
    while(index<k)
    {
        int tag=0;
        loop(i,0,n)
        if(counter[i].time_first<counter[tag].time_first)tag=i;//找出哪个队先走人
        counter[tag].q.pop();//走一个
        counter[tag].q.push(index);//进一个
        if(counter[tag].time_end>=maxTime)book[index]=true;//判断前面的人完成的时候,是不是关门了
        //printf("debug: %d\n",counter[tag].time_end);
        counter[tag].time_end+=cost[index];//记录进去的人什么时候出来
        ans[index]=counter[tag].time_end;
        int top=counter[tag].q.front();
        counter[tag].time_first+=cost[top];//更新下一个人出来的时间
        index++;
    }
}

void Input()
{
    scanf("%d%d%d%d",&n,&m,&k,&q);
    if(!m)m=1;
    int i;
    loop(i,0,k)scanf("%d",&cost[i]);
    Solve();
    int j;
    loop(i,0,q)
    {
        scanf("%d",&j);
        if(book[j-1])
            printf("Sorry\n");
        else
            printf("%02d:%02d\n",8+(ans[j-1]/60),ans[j-1]%60);
    }
}

int main()
{
    Input();
    return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值