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 */
我很多时候做这种处理事务的模拟题,喜欢提前处理后面的事务。但是这样很容易出错,可能有很多情况没有考虑到。
比如我这种方法,如果在处理队列里的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 }