吐槽
这真的是毒瘤题,调试到哭。
思路
vip机制:
1. 若等待队列中有vip,且有vip桌空闲,则优先服务vip
2. 有vip无vip球桌,则vip视为普通人
有vip桌无vip,则vip桌视为普通球桌
情况1:有空余球桌
符合机制1:则优先处理
不符合机制1:则常规处理
情况2:没有空余球桌
求最早结束时间,
符合机制1:则优先处理
不符合机制1:则常规处理
ps: y总思路是真的很清晰
细节和技巧
- 细节注意:
1)打球时间不超过2小时,其以分钟为单位
2)输出等待时间,需四舍五入
3)超过21:00后结束
4) - 技巧
1)设置哨兵,减少判空语句
2)将情况1转化为情况2的操作
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int M = 110;
const int INF = 1e9;
struct Person{
int arrive_time, play_time;
int start_time, waiting_time;
bool operator< (const Person& t) const { //sort排序
if (start_time != t.start_time) return start_time < t.start_time;
return arrive_time < t.arrive_time;
}
bool operator> (const Person& t) const { //优先队列比较大小
return arrive_time > t.arrive_time;
}
};
struct Table {
int id, end_time;
bool operator> (const Table& t) const { //优先队列比较大小
if (end_time != t.end_time) return end_time > t.end_time;
return id > t.id;
}
};
bool is_vip_table[M];
int table_cnt[M];
vector<Person> persons;
void assign(priority_queue<Person, vector<Person>, greater<Person>>& ps,
priority_queue<Table, vector<Table>, greater<Table>>& ts) {// 注意引用
auto p = ps.top(); ps.pop();
auto t = ts.top(); ts.pop();
p.start_time = t.end_time;
p.waiting_time = round((p.start_time - p.arrive_time) / 60.0);
table_cnt[t.id]++;
ts.push({t.id, t.end_time + p.play_time});
persons.push_back(p);
}
string get_time(int secs) {
char str[20];
sprintf(str, "%02d:%02d:%02d", secs / 3600, secs % 3600 / 60, secs % 60);
return str;
}
int main() {
// freopen("H:\\in.txt", "r", stdin);
int n, k, m;
cin >> n;
priority_queue<Person, vector<Person>, greater<Person>> normal_persons;
priority_queue<Person, vector<Person>, greater<Person>> vip_persons;
normal_persons.push({INF}); //哨兵,避免出现过多判空
vip_persons.push({INF});
for (int i = 0; i < n; i++) {
int hh, mm, ss, play_time, is_vip;
scanf("%d:%d:%d %d %d", &hh, &mm, &ss, &play_time, &is_vip);
int secs = hh * 3600 + mm * 60 + ss;
play_time = min(2 * 3600, play_time * 60);
if (is_vip) vip_persons.push({secs, play_time});
else normal_persons.push({secs, play_time});
}
priority_queue<Table, vector<Table>, greater<Table>> normal_tables;
priority_queue<Table, vector<Table>, greater<Table>> vip_tables;
normal_tables.push({1,INF});
vip_tables.push({1,INF});
cin >> k >> m;
for (int i = 0; i < m; i++) {
int id;
cin >> id;
is_vip_table[id] = true;
}
for (int i = 1; i <= k; i++) {
if (is_vip_table[i]) vip_tables.push({i, 8 * 3600});
else normal_tables.push({i, 8 * 3600});
}
while (normal_persons.size() > 1 || vip_persons.size() > 1) {
auto np = normal_persons.top();
auto vp = vip_persons.top();
int arrive_time = min(np.arrive_time, vp.arrive_time);
//将情况1转化为情况2,避免过多讨论
while (normal_tables.top().end_time < arrive_time) { //O(Nklogk)
auto t = normal_tables.top();
normal_tables.pop();
t.end_time = arrive_time;
normal_tables.push(t);
}
while (vip_tables.top().end_time < arrive_time) {
auto t = vip_tables.top();
vip_tables.pop();
t.end_time = arrive_time;
vip_tables.push(t);
}
auto nt = normal_tables.top();
auto vt = vip_tables.top();
int end_time = min(nt.end_time, vt.end_time);
// cout << get_time(arrive_time) << ' ' << get_time(end_time) << '\n';
if (end_time >= 21 * 3600) break;//打样
if (vp.arrive_time <= end_time && vt.end_time == end_time) //优先服务vip
assign(vip_persons, vip_tables);
else if (np.arrive_time < vp.arrive_time) {
if (nt > vt) assign(normal_persons, vip_tables);
else assign(normal_persons, normal_tables);
} else {
if (nt > vt) assign(vip_persons, vip_tables);
else assign(vip_persons, normal_tables);
}
}
sort (persons.begin(), persons.end());
for (auto p : persons) {
cout << get_time(p.arrive_time) << ' ' << get_time(p.start_time) << ' ';
cout << p.waiting_time << '\n';
}
cout << table_cnt[1];
for (int i = 2; i <= k; i++)
cout << ' ' << table_cnt[i];
cout << "\n";
return 0;
}
如果不设哨兵,需要增加哪些判空过程呢
就是你pop的时候需要保证堆非空,取top的时候也要保证堆非空。
明白了,多谢