pat甲级 1026

参考题解

条理清晰,十分优秀。

除了别人都说过的坑点以外,还要注意:

选服务窗口,不是找上次结束时间最小的,而应该是找下个顾客到来时第一个空闲下来的。

测试用例:

4

08:00:00 30 1

08:10:00 10 1

08:25:00 10 1

09:00:00 10 1

3 1

2

应输出:

08:00:00 08:00:00 0

08:10:00 08:10:00 0

08:25:00 08:25:00 0

09:00:00 09:00:00 0

2 2 0 

 

29分代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;
int N, K, M;
int T[110], cnt[110];
vector<int> ans[110];
char vis[110];
struct node
{
    int a, s, p, d, v;
}pr[10010];

int main()
{
    int hh, mm, ss, p;
    scanf("%d", &N);
    for (int i = 0; i < N; i++) {
        scanf("%d:%d:%d %d %d", &hh, &mm, &ss, &pr[i].p, &pr[i].v);
        pr[i].a = (hh*60+mm)*60+ss, pr[i].s = -1, pr[i].p = min(pr[i].p, 120);
    }
    sort(pr, pr+N, [](node u, node v) { return u.a < v.a; });
    scanf("%d %d", &K, &M);
    for (int i = 0; i < M; i++) {
        scanf("%d", &p);
        vis[p] = 1;
    }
    for (int i = 1; i <= K; i++) T[i] = 8*60*60;
    for (int i = 0; i < N; i++) {
        if (pr[i].s != -1) continue;
        int minn = 22*60*60;
        vector<int> pos;
        for (int j = 1; j <= K; j++)
            if (minn > T[j]) {
                minn = T[j];
                pos.clear();
                pos.push_back(j);
            } else if (minn == T[j]) {
                pos.push_back(j);
            }
        int num = 0;
        while (num < (int)pos.size() && vis[pos[num]] == 0) num++;
        if (pr[i].a <= minn) {
            for (int j = i; j < N && pr[j].a < T[pos[num]] && num <(int)pos.size(); j++) {
                // printf("%d %d %d %d\n", j, pr[j].a, minn, pr[j].v);
                if (pr[j].v) {
                    pr[j].s = max(pr[j].a, T[pos[num]]);
                    if (pr[j].s < 21*60*60) {
                        T[pos[num]] = pr[j].s + pr[j].p*60;
                        cnt[pos[num]]++;
                        ans[pos[num]].push_back(j);
                        do {
                            num++;
                        } while(num < (int)pos.size() && vis[pos[num]] == 0);
                    }
                }
            }
        }
        if (pr[i].s == -1) {
            minn = 22*60*60;
            int p[2] = {-1, -1}, now;
            for(int j = 1; j <= K; j++) {
                if(T[j] <= pr[i].a && p[0] == -1) {
                    p[0] = j;
                    break;
                } else if(minn > T[j]) {
                    minn = T[j];
                    p[0] = j;
                }
            }
            if(pr[i].v) {
                for(int j = 1; j <= K; j++)
                    if(T[j] <= pr[i].a && vis[j]) {
                        p[1] = j;
                        break;
                    }
                if(p[1] != -1) now = p[1];
                else now = p[0];
            } else now = p[0];
            pr[i].s = max(pr[i].a, T[now]);
            if(pr[i].s < 21*60*60) {
                T[now] = pr[i].s + pr[i].p*60;
                cnt[now]++;
                ans[now].push_back(i);
            }
        }
    }
    sort(pr, pr+N, [](node u, node v){ return u.s < v.s; });
    for (int i = 0; i < N; i++) {
        if (pr[i].s == -1 || pr[i].s >= 21*60*60) continue;
        printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",
            pr[i].a/60/60, (pr[i].a/60)%60, pr[i].a%60,
            pr[i].s/60/60, (pr[i].s/60)%60, pr[i].s%60, (pr[i].s-pr[i].a+30)/60 );
    }
    for (int i = 1; i <= K; i++) {
        printf("%d", cnt[i]);
        if (i != K) printf(" ");
        else printf("\n");
    }
    /*for (int i = 1; i <= K; i++) {
        for (int j = 0; j < (int)ans[i].size(); j++)
            printf("%d ", ans[i][j]);
        puts("~");
    }*/
    return 0;
}

/*

9
20:52:00 10 0
08:00:00 20 0
08:02:00 30 0
20:51:00 10 0
08:10:00 5 0
08:12:00 10 1
20:50:00 10 0
08:01:30 15 1
20:53:00 10 1
3 1
2

08:00:00 08:00:00 0
08:01:30 08:01:30 0
08:02:00 08:02:00 0
08:12:00 08:16:30 5
08:10:00 08:20:00 10
20:50:00 20:50:00 0
20:51:00 20:51:00 0
20:52:00 20:52:00 0
3 3 2

3
08:00:00 10 0
08:05:00 5 0
08:08:00 10 1
2 1
2

4
08:00:00 30 1
08:10:00 10 1
08:25:00 10 1
09:00:00 10 1
3 1
2

*/
View Code

我很多时候做这种处理事务的模拟题,喜欢提前处理后面的事务。但是这样很容易出错,可能有很多情况没有考虑到。

比如我这种方法,如果在处理队列里的VIP用户时,不一定是分配了最小的VIP桌子,而是分配了结束时间最早的桌子;而如果改成分配最小的VIP桌子,当队列里有多个VIP用户时,需要重新遍历一次,时间复杂度太高。

不如参考的代码一次只处理一个用户,时间复杂度相同,且不会遗漏情况。

不是需要最巧妙的,而是需要最简单的、最清晰的。

 

备份一下参考代码

  1     #include<iostream>
  2     #include<vector>
  3     #include<set>
  4     #include<algorithm>
  5     using namespace std; 
  6     const int OPEN = 3600 * 8;
  7     const int CLOSE = 3600 * 21;
  8     struct cus{
  9         int arvT, serT = -1, costT, flag; 
 10     };  
 11     vector<cus> Vu; //顾客
 12     int FreeT[101]; //桌子空闲的时间
 13     set<int> VipT;//vip桌子
 14     int SerCnt[101];//每个桌子服务的人数
 15     int N, K, M; 
 16     bool cmp(cus A, cus B) {return A.arvT < B.arvT;} 
 17     bool cmp2(cus A, cus B) {return A.serT < B.serT;} 
 18     int selectT(int arvT){
 19         int ret, min = 123123123;
 20         for (int i = 1; i <= K; i++){
 21             if (arvT >= FreeT[i]){
 22                 ret = i;
 23                 break;
 24             }
 25             else if (FreeT[i] < min){
 26                 min = FreeT[i];
 27                 ret = i;
 28             }
 29         }
 30         return ret;
 31     }  
 32     int VipInQue(int s, int time){
 33         int ret = -1;
 34         for (int i = s; i < Vu.size(); i++){
 35             if (Vu[i].flag == 1 && Vu[i].serT == -1 && Vu[i].arvT < time){
 36                 ret = i;
 37                 break;
 38             }
 39         }
 40         return ret;
 41     } 
 42     int vipTable(int arvT){
 43         int ret = -1;
 44         for (auto it = VipT.begin(); it != VipT.end(); it++) {
 45             if (FreeT[*it] <= arvT) {
 46                 ret = *it;
 47                 break;
 48             }
 49         } 
 50         return ret;
 51     } 
 52     int main(){
 53         scanf("%d", &N);
 54         int x;
 55         for (int i = 0; i < N; i++){
 56             int h, m, s;
 57             cus tmp;
 58             scanf("%d:%d:%d %d %d", &h, &m, &s, &tmp.costT, &tmp.flag);
 59             tmp.arvT = 3600 * h + 60 * m + s; 
 60             if (tmp.costT > 120)
 61                 tmp.costT = 120;
 62             tmp.costT *= 60;
 63             Vu.push_back(tmp);
 64         }
 65         scanf("%d%d", &K, &M); 
 66         for (int i = 0; i < M; i++) {
 67             scanf("%d", &x);
 68             VipT.insert(x);
 69         }  
 70         fill(FreeT, FreeT + 101, OPEN);
 71         sort(Vu.begin(), Vu.end(), cmp);
 72         for (int i = 0; i < Vu.size();){
 73             if (Vu[i].serT != -1){//如果该顾客已经安排过,安排下一位
 74                 i++;
 75                 continue;
 76             } 
 77             int t = selectT(Vu[i].arvT);
 78             if (VipT.find(t)!= VipT.end() && Vu[i].flag == 0 && VipInQue(i + 1, FreeT[t]) != -1){
 79                 //选中的空闲桌是vip桌,队首不是vip,并且队列里有排队的vip
 80                 x = VipInQue(i + 1, FreeT[t]);//将这个空闲vip桌分配给队列中第一个vip
 81                 Vu[x].serT = FreeT[t];
 82                 FreeT[t] = Vu[x].serT + Vu[x].costT;
 83                 if (Vu[x].serT < CLOSE)
 84                     SerCnt[t]++;
 85             }
 86             else if (VipT.find(t) == VipT.end() && Vu[i].flag == 1 && vipTable(Vu[i].arvT) != -1) {
 87                 //选中的桌子不是vip桌子,但是队首是vip,且有空闲的vip桌子
 88                 x = vipTable(Vu[i].arvT); //找一个vip桌分配给队首
 89                 Vu[i].serT = Vu[i].arvT;
 90                 FreeT[x] = Vu[i].serT + Vu[i].costT;
 91                 if (Vu[i].serT < CLOSE)
 92                     SerCnt[x]++;
 93                 i++;
 94             }
 95             else{
 96                 if (Vu[i].arvT >= FreeT[t]) 
 97                     Vu[i].serT = Vu[i].arvT; 
 98                 else
 99                     Vu[i].serT = FreeT[t]; 
100                 FreeT[t] = Vu[i].serT + Vu[i].costT; 
101                 if (Vu[i].serT < CLOSE)
102                     SerCnt[t]++;
103                 i++;
104             }
105         } 
106         sort(Vu.begin(), Vu.end(), cmp2);
107         for (int i = 0; i < Vu.size(); i++){
108             if (Vu[i].serT < CLOSE)
109                 printf("%02d:%02d:%02d %02d:%02d:%02d %d\n", Vu[i].arvT / 3600, (Vu[i].arvT % 3600) / 60, Vu[i].arvT % 60,
110                     Vu[i].serT / 3600, (Vu[i].serT % 3600) / 60, Vu[i].serT % 60, (Vu[i].serT - Vu[i].arvT + 30) / 60);
111         } 
112         for (int i = 1; i <= K; i++){
113             if (i != 1)
114                 printf(" ");
115             printf("%d", SerCnt[i]);
116         } 
117         return 0;
118     }
View Code

 

posted @ 2020-08-03 16:38  参婵  阅读(150)  评论(0编辑  收藏  举报