PAT (Advanced Level) Practice - 1014 Waiting in Line(30 分)

题目链接:点击打开链接

题目大意:

  • 银行排队办理业务,有n个窗口,每个窗口前有黄线,黄线内最多排m个人,剩下的人在黄线外等候
  • 给出k个人,并给出他们办理业务所需要的时间time,查询p个人的办理业务结束时间,如果开始办理业务时超过了17:00,输出sorry
  • 08:00开始办理业务,17:00结束办理业务,如果业务已经开始办理,就继续办理直到办理业务结束窗口才关门。
  • 如果某个窗口有人办理业务结束,黄线外的人去那个窗口的队尾等候,如果两个窗口同时有人办理业务结束,就选择窗口号较小的

解题思路:

  • 从17:00前就已经开始服务的,虽然最终的服务时间超过五点,也不是Sorry,而只有从17点之后才会被开始服务的,会是Sorry。这个很关键,不然会有答案错误的案例。
  • 每个顾客进入到一个队伍之后,就不能再离开这个队伍,即使其他队伍中已经没有人了,也只能等当前队伍前面的人结束之后在本队伍接受服务。
  • 大循环用时间来控制,每分钟轮询检测。

AC 代码

#include<bits/stdc++.h>
#include<cmath>

#define mem(a,b) memset(a,b,sizeof a);
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;

struct node
{
    int id,rest;
    node(){}
    node(int id,int rest):id(id),rest(rest){}
    friend bool operator<(node n1,node n2)
    {
        if(n1.rest==n2.rest) return n1.id>n2.id; // 小->大
        return n1.rest<n2.rest; // 大->小
    }
};

priority_queue<node> pq; // 维护有空窗口的状态
queue<int> q[21]; // int 为客户的 id(从 1 开始)

int w,cap,n,k; // 窗口数 窗口容量 客户数 查询次数
int ans[1010], cost[1010]; // 结果 耗时

void init()
{
    mem(ans,-1); mem(cost,0); // ans -1 是为了标记那些没有被处理的客户,Sorry
    for(int i=0;i<21;i++) while(!q[i].empty()) q[i].pop();
}

void print(int mm)
{
    printf("%02d:%02d\n",mm/60,mm%60);
}

int main()
{
    while(~scanf("%d%d%d%d",&w,&cap,&n,&k))
    {
        init();
        for(int i=1;i<=n;i++) scanf("%d",&cost[i]);

        // 初始化客户排队
        int id=1;
        for(int i=1;i<=cap;i++)
            for(int j=1;j<=w;j++)
                q[j].push(id++);

        // 高能啊,t=[1,540),因为客户消耗的时间一定是正整数,
        // 540 开区间是因为正好这时候是处理最后一批正在服务的客户,放到最后有一个for来处理,
        // 等于的话,否则当中会有把 >540 的情况也算进去。(原本只过了3个点,就去了这个等号后 AC!)
        for(int t=1;t<540;t++)
        {
            while(!pq.empty()) pq.pop();

            for(int i=1;i<=w;i++)
            {
                if(!q[i].empty())
                {
                    int idx=q[i].front();
                    if(t==cost[idx])
                    {
                        q[i].pop();
                        ans[idx]=8*60+t;

                        // 提前计算好下个该队下个客户的出来时间
                        idx=q[i].front();
                        cost[idx]+=t;

                        pq.push(node(i,cap-q[i].size())); // 因为只有走了才有空位,每次 q 都会尽可能的补满
                    }
                }
            }

            // 维护有空窗口的队列,并且客户入队
            int isEpy=1;
            node nd;
            while(isEpy)
            {
                isEpy=0;
                while(!pq.empty() && id<=n)
                {
                    nd=pq.top();
                    pq.pop();
                    q[nd.id].push(id++);
                    nd.rest--;
                    if(nd.rest>0)
                        pq.push(nd);
                    isEpy=1;
                }
            }
        }

        // 维护最后到结束点还在处理业务的客户,只处理一批即可,因为下一批已经关门(被赶走)了
        for(int i=1;i<=w;i++)
        {
            if(!q[i].empty())
            {
                int idx=q[i].front();
                q[i].pop();
                ans[idx]=8*60+cost[idx];
            }
        }

        int sel;
        while(k--)
        {
            scanf("%d",&sel);
            if(ans[sel]==-1) puts("Sorry");
            else print(ans[sel]);
        }
    }

    return 0;
}

/*
2 2 7 5
1 2 6 4 3 535 2
3 4 5 6 7
*/

猜你喜欢

转载自blog.csdn.net/Dream_Weave/article/details/81315766