PAT 1014. Waiting in Line (30)(模拟排队等候)(待修改)

题目

1014. Waiting in Line (30)

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue
Suppose a bank has N windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. The rules for the customers to wait in line are:

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.
Now given the processing time of each customer, you are supposed to tell the exact time at which a customer has his/her business done.

For example, suppose that a bank has 2 windows and each window may have 2 custmers waiting inside the yellow line. There are 5 customers waiting with transactions taking 1, 2, 6, 4 and 3 minutes, respectively. At 08:00 in the morning, customer1 is served at window1 while customer2 is served at window2. Customer3 will wait in front of window1 and customer4 will wait in front of window2. Customer5 will wait behind the yellow line.

At 08:01, customer1 is done and customer5 enters the line in front of window1 since that line seems shorter now. Customer2 will leave at 08:02, customer4 at 08:06, customer3 at 08:07, and finally customer5 at 08:10.

Input

Each input file contains one test case. Each case starts with a line containing 4 positive integers: N (<=20, number of windows), M (<=10, the maximum capacity of each line inside the yellow line), K (<=1000, number of customers), and Q (<=1000, number of customer queries).

The next line contains K positive integers, which are the processing time of the K customers.

The last line contains Q positive integers, which represent the customers who are asking about the time they can have their transactions done. The customers are numbered from 1 to K.

Output

For each of the Q customers, print in one line the time at which his/her transaction is finished, in the format HH:MM where HH is in [08, 17] and MM is in [00, 59]. Note that since the bank is closed everyday after 17:00, for those customers who cannot be served before 17:00, you must output “Sorry” instead.

Sample Input
2 2 7 5
1 2 6 4 3 534 2
3 4 5 6 7
Sample Output
08:07
08:06
08:10
17:00
Sorry

解题思路

  • 1.题目大意是一堆人在等着办业务,告诉你每个人办业务的时间,要你求每个人办完业务是什么时候了。
  • 2.关键是我们把人放到队列等候时(已经放满),下一个事件的触发点是找到第一个先出来的人,这样把这个人排出来,那么又可以把人插进队列了,满了又这样,一直这样循环!
  • 3.还有一道题也有点类似PAT 1026. Table Tennis (30),要找一个事情作为触发点,等写完了那道题在放上来。

报错代码(主要再写一边这道题又得很久,再过几天就要考试了,待修改)

#include<cstdio>
#include<vector>
#include<deque>
using namespace std;
#define INF 0x3f3f3f3f
#define endTime 540
//n windows,m capacity,k customers,q queries
int n,m,k,q;

struct person{
    int h,m,leave,cost;
    person():leave(-1){}
};
struct window{
    int currentTime;
    deque<int> list;
    window():currentTime(0){}
};
vector<person> p;
vector<window> windows;
//找到人最少的那个窗口
int findMinWindows(vector<window> a){
    int minWindow = m,seat = -1;
    for (int i = 0; i < n; ++i) {
        if (a[i].list.size() < minWindow) {
            minWindow = a[i].list.size();
            seat = i;
        }
    }
    //如果seat为-1,则代表所有窗口人数都不比m小,则满了
    return seat;
}
//找到最先走人的那个窗口
int findFirstGo(vector<window> a){
    int fisrtToGo=-1,tem_sum = INF;
    for (int i = 0; i < n; ++i) {
        int topPerson =a[i].list[0];
        if (p[topPerson].cost + windows[i].currentTime < tem_sum) {
            tem_sum = p[topPerson].cost + windows[i].currentTime;
            fisrtToGo = i;
        }
    }
    return fisrtToGo;
}

int main(int argc, char *argv[])
{
    scanf("%d %d %d %d",&n,&m,&k,&q);
    //vector<person> p(k+1);
    p.resize(k+1);
    for (int i = 1; i < k+1; ++i) {
        scanf("%d",&p[i].cost);
    }
    vector<int> queries(q);
    for (int i = 0; i < q; ++i) {
        //cin >> queries[i];
        scanf("%d",&queries[i]);
    }
    //vector<window> windows(n);
    windows.resize(n);
    //对于每一个人
    for (int i = 1; i < k + 1; ++i) {
        //找到人数最小的那个窗口,-1是代表都满了
        int minWindow = findMinWindows(windows);
        //如果没满就把i加入到这个窗口
        if (minWindow!=-1&&windows[minWindow].currentTime<endTime) {
            windows[minWindow].list.push_back(i);
        }
        //如果满了就先找到最先走人的那个窗口,把人搞走
        else if(minWindow==-1){
            //找到最先走人的那个窗口,什么样是最先走人的呢?
            //肯定就的给window加个当前时间,如果当前时间+第一个
            //客户用的时间最小,那么最先走人。
            int firstGoW = findFirstGo(windows);
            if (firstGoW!=-1) {
                //赶走他,并记录它走的时间和更新currentTime
                int topPerson = windows[firstGoW].list[0];
                windows[firstGoW].list.pop_front();
                windows[firstGoW].currentTime += p[topPerson].cost;
                p[topPerson].leave = windows[firstGoW].currentTime;
                //搞走之后咋办了,这个人就跳过了吗?
                i--;
            }
        }
    }
    //现在是把所有的都加完了,则要把每个window的人的业务办完
    for (int i = 0; i < n; ++i) {
        while (!windows[i].list.empty()) {
            int topPerson = windows[i].list.front();
            //把它赶走并更新currentTime和这个人离开的时间
            windows[i].list.pop_front();
            p[topPerson].leave = windows[i].currentTime = windows[i].currentTime + p[topPerson].cost;
        }
    }

    for (int i = 0; i < q; ++i) {
        int id = queries[i];
        p[id].h = 8 + p[id].leave / 60;
        p[id].m = p[id].leave % 60;
        if (p[id].leave > endTime ||p[id].leave==-1) {
            printf("Sorry\n");
        }else {
            printf("%02d:%02d\n",p[id].h,p[id].m);
        }
    }
    return 0;
}

AC代码

#include<iostream>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
using  namespace std;
const int endTime=540;//8点开始计时的分
int tp,w,v,tq;
struct window{
    int curTime;
    int curV;
    queue<int> line;
};
struct visitor{
    int win;
    int need;
    int end;
};
vector<window> wins;
vector<visitor> vis;
int findAviableWin()//返回人数最少的窗口号
{
    int i;
    int seat=-1;
    int tot=v;
    for(i=0;i<w;++i)
        if(wins[i].curV<tot)
        {
            tot=wins[i].curV;
            seat=i;
        }
    return seat;
}
void batchServe(){//clear 队列中的客户
    int i,j;
    int visNo;
    for(i=0;i<w;++i){
        while(!wins[i].line.empty()){
            visNo=wins[i].line.front();
            if(wins[i].curTime>=endTime)
                break;
            wins[i].curTime+=vis[visNo].need;
            vis[visNo].end=wins[i].curTime;
            wins[i].line.pop();
            --wins[i].curV;
        }
    }
}
int finishEarliest(){//找到最早有空闲位置的窗口
    int i;
    int seat=0;
    int sum=0xfffffff;
    for(i=0;i<w;++i){
        if(wins[i].curTime+vis[wins[i].line.front()].need<sum){
            sum=wins[i].curTime+vis[wins[i].line.front()].need;
            seat=i;
        }
    }
    return  seat;
}
void process(){
    int i;
    int win=-1;
    int no;
    bool have=false;
    for (i = 0; i < tp; ++i)
    {
        if(!have)
            win=findAviableWin();
        if(win!=-1)//若有空闲位就将客户排入黄线内
        {
            vis[i].win=win;
            wins[win].line.push(i);
            ++wins[win].curV;
            have=false;
        }
        else{//无空闲位,这时开始处理客户,腾出空位
            have=true;
            win=finishEarliest();
            if(wins[win].curTime>=endTime)
                break;
            no=wins[win].line.front();
            wins[win].curTime+=vis[no].need;
            vis[no].end=wins[win].curTime;
            wins[win].line.pop();
            --wins[win].curV;//已经服务过的客户出队
            --i;//重新进行处理
        }
    }
    batchServe();
}
int main(int argc, char const *argv[])
{
    /* code */
    scanf("%d%d%d%d",&w,&v,&tp,&tq);
    int i;
    for(i=0;i<w;++i){
        window tmp;
        tmp.curTime=0;
        tmp.curV=0;
        wins.push_back(tmp);
    }
    for(i=0;i<tp;++i){
        visitor tmp;
        scanf("%d",&tmp.need);
        tmp.end=tmp.win=-1;
        vis.push_back(tmp);
    }
    process();
    int query;
    for(i=0;i<tq;++i)
    {
        scanf("%d",&query);
        --query;
        if(vis[query].end!=-1)
            printf("%02d:%02d\n",vis[query].end/60+8,vis[query].end%60);
        else
            printf("Sorry\n");
    }
    return 0;
}

测试用例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值