。。才得知这类题目不考了。。
那就简单记录一下代码。。这个有几个点通不过我也不知道为什么,逻辑上和柳神的没啥区别。。可能是我哪里边界出错了,不考模拟的话不再深究
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int K = 111; //球桌数目
const int INF = 100000; //无穷大
struct player {
int arriveTime, startTime, serveTime;
bool isVip;
}newplayer;
struct Table {
int endTime, numsever;
bool isVip;
}table[K];
vector<player> Player;
int converseTime(int h, int m, int s) {
return h * 3600 + m * 60 + s;
}
//用到来时间排序用于数据的处理
bool cmpArriveTime(player a, player b) {
return a.arriveTime < b.arriveTime;
}
//用开始时间排序,用于最后的输出
bool cmpStartTime(player a, player b) {
return a.startTime < b.startTime;
}
//寻找下一个vip
int nextVipPlaer(int vipi) {
vipi++;
while (vipi < Player.size() && Player[vipi].isVip == false ) {
vipi++;
}
return vipi;
}
//将pid号球员分配给tid号球桌
void allotTable(int pid, int tid) {
if (Player[pid].arriveTime <= table[tid].endTime) {
Player[pid].startTime = table[tid].endTime;
}
else {
Player[pid].startTime = Player[pid].arriveTime;
}
table[tid].endTime = Player[pid].startTime + Player[pid].serveTime;
table[tid].numsever++;
}
int main() {
int n, k, m, VipTable;
scanf_s("%d", &n);
int stTime = converseTime(8, 0, 0);
int endTime = converseTime(21, 0, 0);
for (int i = 0; i < n; i++) {
int h, m, s, playtime, isVip;
scanf_s("%d:%d:%d %d %d", &h, &m, &s, &playtime, &isVip);
newplayer.arriveTime = converseTime(h, m, s);
newplayer.isVip = isVip;
newplayer.startTime = endTime;
//到达时间比结束时间晚,直接不予进队
if (newplayer.arriveTime >= endTime) continue;
//训练时间大于2h按照2h处理
newplayer.serveTime = playtime <= 120 ? playtime * 60 : 7200;
Player.push_back(newplayer);
}
scanf_s("%d %d", &k, &m);
for (int i = 1; i <= k; i++) {
table[i].endTime = stTime;
table[i].numsever = table[i].isVip = 0;
}
for (int i = 0; i < m; i++) {
scanf_s("%d", &VipTable);
table[VipTable].isVip = 1;
}
sort(Player.begin(), Player.end(), cmpArriveTime);
int i = 0, Vipi = -1; // 给vipi初值为 -1,防止第一个球员就是vip使得其被跳过
Vipi = nextVipPlaer(Vipi);
while (i < Player.size()) {
//找最快结束的球桌
int idx = -1, minEndTime = INF;
for (int j = 1; j <= k; j++) {
if (table[j].endTime < minEndTime) {
idx = j;
minEndTime = table[j].endTime;
}
}
//最快结束的球桌都已经超过了时间,则关门
//这步的目的是因为有可能球员来的时候没关门但是轮到他训练前关门了
if (table[idx].endTime >= endTime) break;
//这个vip球员已经被服务过了,直接跳过他
if (Player[i].isVip == 1 && i < Vipi) {
i++;
continue;
}
//下面分别按照球桌是否是VIP,球员是否是VIP四种情况进行讨论
if (table[idx].isVip == 1) {
if (Player[i].isVip == 1) { //球桌是vip, 球员也是vip
allotTable(i, idx);
if (Vipi == i) Vipi = nextVipPlaer(Vipi); //当前就是vip球员,所以找下一个vip
i++;
}
else { //球桌是vip,球员不是vip
//如果队列里有vip球员,则让他插队
//注:Vipi这个数会永远存在,因为寻找到过程判断条件有一个是越界,所以在这里也要判断一下是否还有vip
if (Vipi <Player.size() && Player[Vipi].arriveTime <= table[idx].endTime) {
allotTable(Vipi, idx);
Vipi = nextVipPlaer(Vipi);
}
else {
allotTable(i, idx);
i++;
}
}
}
else {
if (Player[i].isVip == 0) { //球桌是vip桌,球员不是vip
allotTable(i, idx);
i++;
}
else { //球桌不是vip,球员是vip
//找到结束的vip桌
int VipIdx = -1, minviptime = INF;
for (int j = 1; j <= k; j++) {
if (table[j].endTime < minviptime && table[j].isVip == 1) {
minviptime = table[j].endTime;
VipIdx = j;
}
}
if (VipIdx != -1 && table[VipIdx].endTime <= Player[i].arriveTime) {
//vip桌存在,且空闲时间比球员来得早(其实就是和普通桌一起空闲)
//分配给vip球员
allotTable(i, VipIdx);
if (Vipi == i) Vipi = nextVipPlaer(Vipi);
i++;
}
else {
allotTable(i, idx);
if (Vipi == i) Vipi = nextVipPlaer(Vipi);
i++;
}
}
}
}
sort(Player.begin(), Player.end(), cmpStartTime);
for (int i = 0; i < Player.size() && Player[i].startTime < endTime; i++) {
int ta = Player[i].arriveTime;
int ts = Player[i].startTime;
printf("%02d:%02d:%02d ", ta / 3600, ta % 3600 / 60, ta % 60);
printf("%02d:%02d:%02d ", ts / 3600, ts % 3600 / 60, ts % 60);
printf("%.0f\n", round(ts - ta) / 60.0);
}
for (int i = 1; i <= k; i++) {
printf("%d", table[i].numsever);
if (i < k) printf(" ");
}
return 0;
}