题目:
题目链接:https://pintia.cn/problem-sets/994805342720868352/problems
思路:
感觉我的思路比较清奇, 导致代码写的比较长…
我的思路是: 建立一个客户列表,时间按照秒保存,按照到达时间排序; 桌子放入一个列表, 桌子的结构包括一个计数器,一个释放时间,一个vip的标签; 这样数据就准备好了开始干坏事.
在一个大循环里:
- 更新最早有桌子释放的时间, 以及桌子的索引.
- 读客户列表, 如果客户的到达时间在最早释放时间之前, 就让他进入队列, 并继续读列表,直到列表的中的下一个客户的到达时间最早有桌子释放的时间晚为止.队列里这些人就是在最早有桌子释放的时候,正在排队的人.
- 开始安排客户
如果队列不为空, 则从队列中安排一个人上桌, 如果队列为空,则安排用户列表中下一个人,不用等直接上桌.
队列中有人时:- 如果当前释放的桌子是普通桌子, 直接安排队列最前面的人上桌
- 如果当前释放的桌子是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;
}
}