解题思路:
相当复杂的模拟题,而且隐藏的条件很多。
1.注意输入数据的处理,把时间统一成秒会方便很多。
2.将顾客按到达时间排序后,按顺序处理,注意维护一个vip顾客的队列,每次找出最早空出来的桌子。
3.我将情况分为了以下四种分别处理(以下所说顾客均为队首且未被服务过的顾客,桌子均为找到的最早空闲的桌子):
1) 顾客为vip, 桌子为vip :直接分配即可。
2)顾客为vip, 桌子非vip :找到最早空闲的vip桌子,如果vip桌子的空闲时间比顾客到达时间早, 分配给顾客vip桌子
否则,分配当前桌子。
3)顾客非vip,桌子为vip:如果vip队列首位顾客到达时间早于桌子空闲时间,则把桌子分配给该vip顾客,本轮顾客放到下一轮处理,否则直接分配桌子给当前顾客。
4)顾客非vip, 桌子非vip:直接分配即可。
注意:题目中有一些限制,比如单对顾客不能打球超过120分钟,21:00:00 (含21:00:00)以后抵达的顾客均不提供服务。
代码如下(还有一些冗余,不过思路还算清晰):
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 10000 + 5;
const int maxt = 100 + 5;
const int INF = 0x3fffffff;
const int maxTime = 21 * 3600; // 晚上21:00
int n, t, m;
struct Table
{
int vip;
int lastTime; // 桌子能空出来的时间
int serveNum; // 服务的人数
}table[maxt];
struct Player
{
int vip, served; //vip 以及是否被服务过
int arrTime; // 到达时间
int playTime; // 运动时间
int serveTime; // 开始时间
}player[maxn];
vector<int> vipPlayer; //存储vip客人的序号
bool cmp1(Player a, Player b)
{
return a.arrTime < b.arrTime;
}
bool cmp2(Player a, Player b)
{
return a.serveTime < b.serveTime;
}
void solve()
{
int i = 0, v = 0; // v 表示服务到第v个vip队列里的客人
while(i < n)
{
if(player[i].served) {i++; continue;}
int tid = -1, tlast = INF; //寻找最早空出来的桌子
for(int j = 0; j < t; j++)
{
if(tlast > table[j].lastTime)
{
tid = j;
tlast = table[j].lastTime;
}
if(tlast <= player[i].arrTime) break;
}
if(tlast >= maxTime || player[i].arrTime >= maxTime) break; //桌子空闲时间或抵达时间大于21:00,直接退出
if(player[i].vip)
{
if(table[tid].vip) // 空闲桌子和顾客均为vip,直接分配
{
player[i].serveTime = player[i].arrTime > tlast ? player[i].arrTime : tlast;
table[tid].serveNum++;
table[tid].lastTime = player[i].serveTime + player[i].playTime;
}
else // 桌子不是vip
{
if(tlast > player[i].arrTime) // 如果桌子空出来的时间比当前时间队列最前的顾客的到达时间还要晚,直接分配
{
player[i].serveTime = tlast;
table[tid].serveNum++;
table[tid].lastTime = player[i].serveTime + player[i].playTime;
}
else // 桌子空出来的时间比顾客到达的时间要早
{
int tvip, viplast = INF;
for(int j = 0; j < t; j++) // 寻找最早空出来的vip桌子
if(viplast > table[j].lastTime && table[j].vip)
{
tvip = j;
viplast = table[j].lastTime;
}
if(player[i].arrTime >= viplast) // vip桌子空出来比顾客到达时间早,分配vip桌子
{
player[i].serveTime = player[i].arrTime;
table[tvip].serveNum++;
table[tvip].lastTime = player[i].serveTime + player[i].playTime;
}
else // 分配当前桌子
{
player[i].serveTime = player[i].arrTime;
table[tid].serveNum++;
table[tid].lastTime = player[i].serveTime + player[i].playTime;
}
}
}
player[i].served = 1;
v++;i++;
}
else //顾客非vip
{
if(table[tid].vip) //桌子为vip
{
if(v < vipPlayer.size() && player[vipPlayer[v]].arrTime <= tlast) // 如果vip队列首位顾客的到达时间比当前vip桌子空出来的时间早
{ // 分配给vip队列队首的顾客
Player& now = player[vipPlayer[v]];v++;
now.serveTime = tlast;
now.served = 1;
table[tid].serveNum++;
table[tid].lastTime = now.serveTime + now.playTime;
}
else//直接分配给当前顾客
{
player[i].serveTime = player[i].arrTime > tlast ? player[i].arrTime : tlast;
table[tid].serveNum++;
table[tid].lastTime = player[i].serveTime + player[i].playTime;
player[i].served = 1;
i++;
}
}
else //桌子非vip,直接分配
{
player[i].serveTime = player[i].arrTime > tlast ? player[i].arrTime : tlast;
table[tid].serveNum++;
table[tid].lastTime = player[i].serveTime + player[i].playTime;
player[i].served = 1;
i++;
}
}
}
sort(player, player+n, cmp2);//按开始时间排序
}
void print()//输出
{
for(int i = 0; i < n; i++)
{
if(player[i].serveTime >= maxTime) break;
printf("%02d:%02d:%02d ", player[i].arrTime/3600, player[i].arrTime%3600/60, player[i].arrTime%60);
printf("%02d:%02d:%02d ", player[i].serveTime/3600, player[i].serveTime%3600/60, player[i].serveTime%60);
printf("%d\n", (player[i].serveTime-player[i].arrTime)/60+((player[i].serveTime-player[i].arrTime)%60 < 30 ? 0:1));
}
for(int i = 0; i < t; i++)
if(i) printf(" %d", table[i].serveNum);
else printf("%d", table[i].serveNum);
printf("\n");
}
int main()
{
while(scanf("%d", &n) == 1)
{
vipPlayer.clear();
for(int i = 0; i < n; i++)
{//这里把时间都转换成秒,方便计算和排序
int hh, mm, ss, p, v;
scanf("%d:%d:%d %d %d", &hh, &mm, &ss, &p, &v);
player[i].arrTime = hh * 3600 + mm * 60 + ss;
p = p > 120 ? 120 : p;
player[i].playTime = p*60;
player[i].vip = v;
player[i].serveTime = INF;
player[i].served = 0;
}
sort(player, player+n, cmp1);
for(int i = 0; i < n; i++)
if(player[i].vip) vipPlayer.push_back(i);
scanf("%d", &t);
for(int i = 0; i < t; i++)
{
table[t].lastTime = 8 * 3600;
table[t].vip = 0;
table[t].serveNum = 0;
}
scanf("%d", &m);
for(int i = 0; i < m; i++)
{
int x;
scanf("%d", &x);
x--;
table[x].vip = 1;
}
solve();
print();
}
return 0;
}