PTA 甲级 1014 Waiting in Line (30 分) 【排队论??】【模拟】

参考博客

题目

n个窗口,每个窗口可以排队m人。有k位用户需要服务,给出了每位用户需要的minute数,所有客户在8点开始服务,如果有窗口还没排满就入队,否则就在黄线外等候。如果有某一列有一个用户走了服务完毕了,黄线外的人就进来一个。如果同时就选窗口数小的。求q个人的服务结束时间。
如果一个客户在17:00以及以后还没有开始服务(此处不是结束服务是开始17:00)就不再服务输出sorry;如果这个服务已经开始了,无论时间多长都要等他服务完毕

输入N, M , K, Q

接下来K个数字,是这些用户需要的操作时间。

最后一行的Q个数字,是询问的用户的排序。

决定只贴上题目中的排队规则:

  • The space inside the yellow line in front of each window is enough to contain a line with M customers. Hence when all the N lines are full, all the customers after (and including) the (NM+1)st one will have to wait in a line behind the yellow line.
  • Each customer will choose the shortest line to wait in when crossing the yellow line. If there are two or more lines with the same length, the customer will always choose the window with the smallest number.
  • Customer​i​​ will take T​i​​ minutes to have his/her transaction processed.
  • The first N customers are assumed to be served at 8:00am.

分析

这道题,是个模拟。但是我想了想,不知道怎么去模拟。看了题解才知道自己忘记了一个重要的假设:假设这K个人是同时到来的! 然后还是不太会做。23333.

第一阶段,是前M * N个顾客,他们一定是已知自己排在哪个窗口的。因为毕竟同时到来,不把黄线内的区域填满是不会罢休的;而且每个人都会找排队短的,序号小的,那大家就排完一行,再排一行。

第二阶段,如果这M * N 个顾客不到K个,还有其他顾客,剩余的这些顾客就要看哪些窗口先有人离开了。哪个窗口先有人离开,看的是poptime 。poptime的初始化在前一阶段(第一行顾客的操作时间,也即第二个阶段这个窗口的第一个顾客到来时间)。这时的操作,将队列首部的顾客弹出去,将当前顾客加入队尾,需要修改该窗口的poptime(为弹出顾客后队首顾客的操作时间)。窗口的endtime 是跟 res一同进行改变 , 加上新来的顾客的操作时间。

总而言之,这种有着时间顺序的模拟,不太熟练。记得之前有个网络赛猫吃鱼什么的,差不多??

代码

还是直接看柳神的代码吧柳神的代码

我大概相当于赋值粘贴了。


typedef long long ll;
const int maxn = 1005;
int N , M , K, Q;
int optime[maxn]; //每个人的操作时间

struct Node
{
    queue < int > q;
    int poptime ;
    int endtime;
};

int res[maxn];//记录每个人的完成时间
int unserved[maxn];
int main()
{
    cin >> N >> M >> K >> Q;//N 个窗户 , M 个人排队

    vector < Node > windows(N + 1);//每个窗口下的排队
    memset(unserved , 0 , sizeof(unserved));

    for(int i = 1 ; i <= K ; i++)
        cin >> optime[i];

    int idx = 1;
    for(int i = 1; i <= M ; i ++)
    {
        for(int j = 1; j <= N ; j++)
        {
            if(idx <= K)
            {
                windows[j].q.push(optime[idx]);
                if(windows[j].endtime >= 540)
                    unserved[idx] = 1;

                windows[j].endtime += optime[idx];
                if( i == 1)
                    windows[j].poptime = optime[idx];
                res[idx] = windows[j].endtime;
                idx ++;
            }
        }
    }
    while( idx <= K)
    {
        int minidx = 1 , mintime = windows[1].poptime;
        for(int i = 2; i <= N ; i++)
        {
            if(mintime > windows[i].poptime)
            {
                mintime = windows[i].poptime;
                minidx = i;
            }
        }

        windows[minidx].q.pop();
        windows[minidx].q.push(optime[minidx]);
        windows[minidx].poptime += windows[minidx].q.front();
        if(windows[minidx].endtime >= 540)
            unserved[idx] = 1;
        windows[minidx].endtime += optime[idx];
        res[idx] = windows[minidx].endtime;
    
   //     cout << idx << "  " << res[idx] << endl;
        idx ++;
    }

    for(int i = 1 ; i <= Q; i++)
    {
        int check;
        cin >> check;
        if(unserved[check] == 1)
            cout << "Sorry" << endl;
        else
        {
            printf("%02d:%02d\n" , res[check]/60 + 8 , res[check] % 60);
        }
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值