天天看点

PAT (Advanced Level) Practise 1026 Table Tennis (30)

1026. Table Tennis (30)

时间限制

400 ms

内存限制

65536 kB

代码长度限制

16000 B

判题程序

Standard

作者

CHEN, Yue

A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For any pair of players, if there are some tables open when they arrive, they will be assigned to the available table with the smallest number. If all the tables are occupied, they will have to wait in a queue. It is assumed that every pair of players can play for at most 2 hours.

Your job is to count for everyone in queue their waiting time, and for each table the number of players it has served for the day.

One thing that makes this procedure a bit complicated is that the club reserves some tables for their VIP members. When a VIP table is open, the first VIP pair in the queue will have the priviledge to take it. However, if there is no VIP in the queue, the next pair of players can take it. On the other hand, if when it is the turn of a VIP pair, yet no VIP table is available, they can be assigned as any ordinary players.

Input Specification:

Each input file contains one test case. For each case, the first line contains an integer N (<=10000) - the total number of pairs of players. Then N lines follow, each contains 2 times and a VIP tag: HH:MM:SS - the arriving time, P - the playing time in minutes of a pair of players, and tag - which is 1 if they hold a VIP card, or 0 if not. It is guaranteed that the arriving time is between 08:00:00 and 21:00:00 while the club is open. It is assumed that no two customers arrives at the same time. Following the players' info, there are 2 positive integers: K (<=100) - the number of tables, and M (< K) - the number of VIP tables. The last line contains M table numbers.

Output Specification:

For each test case, first print the arriving time, serving time and the waiting time for each pair of players in the format shown by the sample. Then print in a line the number of players served by each table. Notice that the output must be listed in chronological order of the serving time. The waiting time must be rounded up to an integer minute(s). If one cannot get a table before the closing time, their information must NOT be printed.

Sample Input:

9
20:52:00 10 0
08:00:00 20 0
08:02:00 30 0
20:51:00 10 0
08:10:00 5 0
08:12:00 10 1
20:50:00 10 0
08:01:30 15 1
20:53:00 10 1
3 1
2      

Sample Output:

08:00:00 08:00:00 0
08:01:30 08:01:30 0
08:02:00 08:02:00 0
08:12:00 08:16:30 5
08:10:00 08:20:00 10
20:50:00 20:50:00 0
20:51:00 20:51:00 0
20:52:00 20:52:00 0

3 3 2      

又是模拟排队的问题,此题坑点很多,我在代码中打了注释的地方都是需要注意的。

不得不说,此题的数据应该是水了,对于到达时有多个桌子空出的情况我一开始选择的是最小的,竟然可以对。

#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<iostream>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF = 0x7FFFFFFF;
const int maxn = 1e5 + 10;
int n, f[maxn], t[maxn], x, y, z, m, u, vis[maxn], cnt[maxn];

struct point
{
  int x, y, f;
  bool operator<(const point &a)const
  {
    return x < a.x;
  }
}a[maxn];

void putout(int x)
{
  printf("%02d:%02d:%02d ", x / 3600, x / 60 % 60, x % 60);
}

void putmin(int x)
{
  printf("%d\n", x / 60 + (x % 60 < 30 ? 0 : 1));//满30秒进1分
}

int main()
{
  scanf("%d", &n);
  for (int i = 0; i < n; i++)
  {
    scanf("%d:%d:%d", &x, &y, &z);
    a[i].x = x * 3600 + y * 60 + z;
    scanf("%d%d", &x, &a[i].f);
    a[i].y = min(x * 60, 7200);//最多不超过2小时
  }
  sort(a, a + n);
  scanf("%d%d", &m, &u);
  while (u--) scanf("%d", &x), f[x] = 1;
  for (int i = 1; i <= m; i++) t[i] = 8 * 3600;
  for (int i = 0; i < n; i++)
  if (!vis[i])
  {
    int now = 1;
    for (int j = 1; j <= m; j++) if (t[now] > t[j]) now = j;//找出最早空出的桌子
    if (max(t[now], a[i].x) >= 21 * 3600) break;//超过21点跳出
    if (t[now] <= a[i].x)//这意味着现在不用排队
    {
      int vip = -1;//如果这个人是vip那么会选择能用的vip的桌子中最小的
      for (int j = m; j >= 1; j--)
      {
        if (t[j] <= a[i].x) now = j;
        if (t[j] <= a[i].x&&f[j]) vip = j;
      }
      if (a[i].f&&vip != -1) now = vip; //如果这个人是vip且有vip的桌子能用
      cnt[now]++;
      putout(a[i].x); putout(a[i].x);
      printf("0\n"); t[now] = a[i].x + a[i].y;
    }
    else//这意味着现在有人在排队
    {
      /*这部分有个问题
      如果有人在排队,并且同时空出了一张非vip桌子和一张vip桌子,
      如果标号小的不是vip,标号大的是vip,那么先处理哪个呢,题目没有明确的指出
      经过我的测试,也没有这样的数据,所以可以忽略。

      int vip = -1; //如果有vip桌子同时也可用
      for (int j = m; j >= 1; j--)
      {
        if (t[j] == t[now] && f[j]) vip = j;
      }
      if (vip != -1)//先选择处理vip桌子
      {
        int flag = 0;
        for (int j = i; j < n&&a[j].x <= t[vip]; j++)
        {
          if (a[j].f&&!vis[j])
          {
            vis[j] = 1;
            putout(a[j].x); putout(t[vip]);
            putmin(t[vip] - a[j].x);
            t[vip] = t[vip] + a[j].y;
            flag = 1; break;
          }
        }
        if (flag) { cnt[vip]++; i--; continue; }
      }
      */
      cnt[now]++;
      if (f[now])   //如果是vip的桌子
      {
        int flag = 0;
        for (int j = i; j < n&&a[j].x <= t[now]; j++)//找到是否有vip在等待
        {
          if (a[j].f&&!vis[j])
          {
            vis[j] = 1;
            putout(a[j].x); putout(t[now]);
            putmin(t[now] - a[j].x);
            t[now] = t[now] + a[j].y;
            flag = 1; break;
          }
        }
        if (flag) i--;
        else//如果没有,那么第一个人用了
        {
          putout(a[i].x); putout(t[now]);
          putmin(t[now] - a[i].x);
          t[now] = t[now] + a[i].y;
        }
      }
      else//非vip桌子,直接用
      {
        putout(a[i].x); putout(t[now]);
        putmin(t[now] - a[i].x);
        t[now] = t[now] + a[i].y;
      }
    }
  }
  for (int i = 1; i <= m; i++) printf("%d%s", cnt[i], i == m ? "\n" : " ");
  return 0;
}