1. 程式人生 > >1026 Table Tennis (30 分)C++實現(已AC)

1026 Table Tennis (30 分)C++實現(已AC)

題目:

題目連結:https://pintia.cn/problem-sets/994805342720868352/problems

思路:

感覺我的思路比較清奇, 導致程式碼寫的比較長…
我的思路是: 建立一個客戶列表,時間按照秒儲存,按照到達時間排序; 桌子放入一個列表, 桌子的結構包括一個計數器,一個釋放時間,一個vip的標籤; 這樣資料就準備好了開始幹壞事.

在一個大迴圈裡:

  1. 更新最早有桌子釋放的時間, 以及桌子的索引.
  2. 讀客戶列表, 如果客戶的到達時間在最早釋放時間之前, 就讓他進入佇列, 並繼續讀列表,直到列表的中的下一個客戶的到達時間最早有桌子釋放的時間晚為止.佇列裡這些人就是在最早有桌子釋放的時候,正在排隊的人.
  3. 開始安排客戶
    如果佇列不為空, 則從佇列中安排一個人上桌, 如果佇列為空,則安排使用者列表中下一個人,不用等直接上桌.
    佇列中有人時:
    • 如果當前釋放的桌子是普通桌子, 直接安排佇列最前面的人上桌
    • 如果當前釋放的桌子是vip桌子, 檢查佇列中是否有vip, 找到第一個vip安排上桌, 如果沒有的話就安排佇列的第一個人上桌.

這道題最重要的是理請集中情況的關係:
普通使用者

  • 有桌(即佇列為空): 選編號最小
  • 無桌: 進入佇列中等待, 當其位於隊首時, 若下一張是普通桌, 則安排, 若是vip桌, 檢查此刻佇列中是否有vip

vip使用者

  • 有桌(即佇列為空): 如果有vip桌, 去編號最小vip桌, 如果沒有, 去最小普通桌
  • 無桌: 進入佇列等待, 每次有桌子釋放時, 檢查是否是vip桌, 如果是, 則選第一個vip上桌, 如果不是則繼續等待直至到隊首.

坑點:

這道題的坑點在另一個大神的部落格中講的很清楚, 同時我覺得那篇部落格最有價值的是構造出了較多的測試用例, 在本題中, 構造測試用例能夠有效探測邏輯錯誤及邊界錯誤是很重要的.
連結如下:https://blog.csdn.net/jmlikun/article/details/49821845

程式碼:


#include
<iostream>
#include<vector> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int OPEN_TIME = 8 * 3600; const int CLOSED_TIME = 21 * 3600; struct Customer { int arrive_time,serve_time, occupied, table; bool vip; }; struct table { int cnt; int release_time; bool for_vip; }; class tables { private: table table_list[100]; int Size; public: tables(int N) { Size = N; for (int i = 0; i < N; i++) { table_list[i].release_time = OPEN_TIME; table_list[i].cnt = 0; table_list[i].for_vip = false; } } int size() { return Size; } void add_vip(int v){ table_list[v].for_vip = true; } void release_time(int &vip_time, int &vip_indx, int &nvip_time, int &nvip_indx); void take_table(Customer &c, int index); void print_serve_cnt(); }; bool cmp_by_arriving_time(Customer c1, Customer c2); bool cmp_by_serve_time(Customer c1, Customer c2); int get_vip(vector<Customer*> q); void print_time(int time_s); int main() { int N; vector<Customer> customer_list; // cin >> N; while (N--) { int hh, mm, ss, serve; bool vip; Customer c; scanf("%d:%d:%d %d", &hh, &mm, &ss, &serve); cin >> vip; // cin >> hh >> mm >> ss >> serve >> vip; c.arrive_time = hh * 3600 + mm * 60 + ss; if (c.arrive_time > CLOSED_TIME) continue; c.occupied = serve * 60; if (c.occupied > 7200) c.occupied = 7200; c.vip = vip; customer_list.push_back(c); } int T, V; cin >> T >> V; tables table_list(T); // while(V--) { int temp; cin >> temp; table_list.add_vip(temp-1); } // handle the input. sort(customer_list.begin(), customer_list.end(), cmp_by_arriving_time); vector<Customer*> queue; int i = 0; // denote the customer who has been processed. while (i < (int)customer_list.size() || !queue.empty()) { int vip_time, vip_index, nvip_time, nvip_index; table_list.release_time(vip_time, vip_index, nvip_time, nvip_index); // update the min release time. int release_time = min(vip_time, nvip_time); int release_index; // release_index = vip_time < nvip_time ? vip_index : nvip_index; 這句邏輯錯誤引起較大的bug, 耽誤了很多時間, 可以通過所有使用者都是普通使用者,而vip桌子在中間的測試用例識別. if (vip_time < nvip_time) release_index = vip_index; else if (vip_time > nvip_time) release_index = nvip_index; else { release_index = vip_index < nvip_index ? vip_index : nvip_index; } // problem: /* if vip_time == nvip_time, which one should be pass to release_index? the one with smaller index? if vip table and nvip_table release at the same time, queue is empty: for not vip, they always choose the one with smallest index, for vip, they choose the vip table of smallest index. queue isn't empty: if the smaller table is vip table, vips will be checked. if the smaller table isn't vip table, give it to the front one in queue. */ while (customer_list[i].arrive_time < release_time && i < (int)customer_list.size()) // if the customers come before release time, just enqueue them. { queue.push_back(&customer_list[i++]); // finish process i++ } // choose one to get a first released table. if (queue.empty()) { // if no one waiting, just occupied the table update the release time. if (customer_list[i].vip) { if (customer_list[i].arrive_time >= vip_time) // has vip table opened table_list.take_table(customer_list[i], vip_index); else// no vip table accessable, but nvip table is accessable. table_list.take_table(customer_list[i], nvip_index); } else { // for not vip customer table_list.take_table(customer_list[i], release_index); // select the one with smallest index. } i++; // finish process i++ } else { // queue isn't empty if (release_index == vip_index ) { // if the first release table is a vip table, check whether there are vips in queue, if true, dequeue the vip from queue. // release_index == vip_index instead of release_time == vip_time, index disdiguishes vip table distinctly but release_time not. int dequeue_index = get_vip(queue); if (dequeue_index == -1) dequeue_index = 0; table_list.take_table(*(queue[dequeue_index]), release_index); queue.erase(queue.begin() + dequeue_index); // remove served customer from queue. } else { // if the first release table is a ordinary one, dequeue the first one in queue. int dequeue_index = 0; table_list.take_table(*(queue[dequeue_index]), release_index); queue.erase(queue.begin() + dequeue_index); // remove served customer from queue. } // dealing with the customers that have been processed, without i++ } } sort(customer_list.begin(), customer_list.end(), cmp_by_serve_time); for (auto p = customer_list.begin();p != customer_list.end(); p++) { if (p->serve_time >= CLOSED_TIME) break; print_time(p->arrive_time); print_time(p->serve_time); int waitMinutes=(p->serve_time - p->arrive_time)/60+((p->serve_time - p->arrive_time)%60<30?0:1); cout << waitMinutes << endl; } table_list.print_serve_cnt(); getchar(); getchar(); return 0; } int get_vip(vector<Customer*> q) { for (int i = 0; i < (int)q.size(); i++) { if (q[i]->vip) return i; } return -1; } void print_time(int time_s) { int hh, mm, ss; hh = time_s / 3600; time_s = time_s % 3600; mm = time_s / 60; ss = time_s % 60; printf("%02d:%02d:%02d ", hh, mm, ss); } bool cmp_by_arriving_time(Customer c1, Customer c2) { return c1.arrive_time < c2.arrive_time; } bool cmp_by_serve_time(Customer c1, Customer c2) { return c1.serve_time < c2.serve_time; } void tables::release_time(int &vip_time, int &vip_indx, int &nvip_time, int &nvip_indx) { vip_time = CLOSED_TIME+1; nvip_time = CLOSED_TIME+1; vip_indx = 0; nvip_indx = 0; for (int i = 0; i < size(); i++) { if (table_list[i].for_vip) { if (table_list[i].release_time < vip_time) { vip_time = table_list[i].release_time; vip_indx = i; } } else { if (table_list[i].release_time < nvip_time) { nvip_time = table_list[i].release_time; nvip_indx = i; } } } } void tables::take_table(Customer &c, int index) { if (table_list[index].release_time > c.arrive_time) // have to wait { c.serve_time = table_list[index].release_time; if (c.serve_time >= CLOSED_TIME) return ; table_list[index].release_time = table_list[index].release_time + c.occupied; } else // not have to wait { c.serve_time = c.arrive_time; if (c.serve_time >= CLOSED_TIME) return ; table_list[index].release_time = c.serve_time + c.occupied; } table_list[index].cnt++; c.table = index; } void tables::print_serve_cnt() { for(int i = 0; i < size(); i++) { if (i == 0) cout << table_list[i].cnt; else cout << " " << table_list[i].cnt; } }