PAT甲级 1026 Table Tennis (30分)大模拟

**

1026 Table Tennis (30分)

**

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 privilege 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

题意:给定n个队(两个人一个队)来训练的时间(HH:MM:SS),然后其中一些队有vip特权,如果有vip桌子空闲,这些队可以优先使用,然后告诉每个队的训练时间(Min),每个队都会优先找到空闲的桌子中序号最小的桌子使用。
这里尤其说明两个问题,按照题目的意思要求:如果有VIP桌子,并且排队等待的队伍中有VIP队伍,VIP队伍可以插队直接使用,如果此时没有VIP队伍,那么VIP桌子可以被普通队伍使用,如果没有VIP桌子,所有队伍一律按时间排队等待。
最后输出答案按每个队被服务的时间从小到大排序,依次输出到达时间,开始服务时间,总的等待时间(等待时间是秒为单位,答案要求输出分为单位,四舍五入),最后一行输出每个桌子服务了多少队伍,这个简单,每个队伍得到服务时就标记加一下数目就行了。并且要求如果某个队伍在21:00之前没有得到服务,就不输出结果,比如样例中20:53:00到达的队伍,需要排队到恰好21:00,就没法得到服务,所以答案中没有输出。

**

题解:

**
本来模拟题目应该是单独实现功能,只是涉及关系比较复杂,其中没有什么算法相关的知识,也就是说不难,只要理解题目都能实现那种,但是刷了好几次PAT甲级题目注意到PAT很喜欢出一些时间问题相关的模拟题,做了几个题目下来也总结了一些处理时间的技巧,特此分享下。

首先说说这个题目,我一开始读完题目,就把代码实现提交,然后。。。就错了,只过了一部分,然后我就反复检查代码,反复读题目(模拟题细节比较多,需要多读题目)但是都没有问题,然后自己生成了很多数据测试也没问题,这样折腾了2个小时后我还是找不到答案错误,,,,然后找了别人通过的代码对比测试,然后吧。。。。。发现又是题目理解错了。

我理解错题意主要有两点:
1.每个队伍服务时间不能超过2个小时,这个题目有说明,看原题目描述。
在这里插入图片描述中文意思为:假设每对选手最多可玩2小时。

然后我就理解成了输入数据中每个队伍的服务时间都不会超过2小时,因为后续的时间处理,如果输入数据中有队伍超过2小时,就要把他们的服务时间处理成2小时,这个信息是比较重要的,但是题目中就是一句话带过,确实比较考究眼力。

2.VIP队伍选择VIP桌子。
我理解成:按桌子序号由小到大遍历(题目要求选择序号小的桌子),如果当前桌子为空,说明可以服务,然后再判断该桌子是否为VIP桌子,如果是先判断下等待的队伍中是否有VIP用户,如果有这个VIP桌子就先服务这个VIP用户,如果没有VIP用户就按当前等待队列中最靠前的队伍使用。如果当前桌子不是VIP桌子,不管等待队列中是否有VIP,都让排在队首的队伍使用。

这样想好像没啥问题,但是这样处理的确是有问题的,因为如果同一个时刻比如桌子1和桌子2都是空闲,但是桌子1是VIP桌子,恰好等待队伍中有VIP用户,假设等待队列为A,B,其中B是VIP。
如果按我的理解实现代码,处理顺序就是A去桌子1,B去桌子2。
但实际因为同时可获得桌子1和桌子2的服务,因为桌子1是VIP,同时有VIP用户B,所以需要先提供给VIP服务,因此正确的服务顺序是VIP用户B优先选择去了VIP桌子1,最后普通用户A去了桌子2。

不知道别人是否犯这样的错,总之需要多注意多考虑情况。

整体处理:先把所有的VIP桌子用来判断去处理队列中的所有VIP用户,处理结束后只有3种情况:(1)没有VIP桌子但有VIP用户,(2)有VIP桌子没有VIP用户(3)没有VIP桌子也没有VIP用户。

这3种情况就是简单的先到先服务了,就是每次先提供给等待队列队首的用户使用,然后分析就是这样了。

说一下处理时间的技巧,题目输入的是标准时间格式:HH:MM:SS,这样一个字符串处理起来未免太麻烦,可以处理成time=H3600+M60+S,也就是把时间化成题目要求处理的最小单位秒,然后就是暴力跑数据,在处理的时候直接训练从8*3600跑到(21+2)*3600,因为截止服务时间为21,然后每个队最多2小时。

最后输出的时候反向转换时间用如下代码:

void Print(int tim)
{
	int h=tim/3600;
	tim%=3600;
	int m=tim/60;
	tim%=60;
	int s=tim;
	if(h<10)
	printf("0%d",h);
	else printf("%d",h);
	printf(":");
	if(m<10)
	printf("0%d",m);
	else printf("%d",m);
	printf(":");
	if(s<10)
	printf("0%d",s);
	else printf("%d",s);
}

最后AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+100;
struct Node
{
	int arrive_time;
	int server_time;
	int now_time;
	int wait_time;
	int vip;
}a[N];
bool cmp(Node a1,Node a2)
{
	return a1.arrive_time<a2.arrive_time;
}
bool cmp2(Node a1,Node a2)
{
	return a1.server_time<a2.server_time;
}
int n,m;
bool vip_table[200];
queue<Node>wait,server[200];
vector<Node>finish;
int ans[200];
void Print(int tim)
{
	int h=tim/3600;
	tim%=3600;
	int m=tim/60;
	tim%=60;
	int s=tim;
	if(h<10)
	printf("0%d",h);
	else printf("%d",h);
	printf(":");
	if(m<10)
	printf("0%d",m);
	else printf("%d",m);
	printf(":");
	if(s<10)
	printf("0%d",s);
	else printf("%d",s);
}
void solve()
{
	memset(ans,0,sizeof(ans));
	sort(a+1,a+1+n,cmp);
	int id=1;
	int ans_vip=0;
	for(int tim=8*3600;tim<24*3600;tim++)
	{
		for(int i=1;i<=m;i++)
		{
			if(server[i].size()==0)continue;
			//说明当前用户服务时间已经完成 
			if(server[i].front().now_time==0)
			{
				ans[i]++;
				//加入答案的输出队列finish 
				finish.push_back(server[i].front());
				server[i].pop();
			}
		}
		//让抵达的人来到等待队列 
		//因为每个人到达时间不同,所以同一时刻只会有一个人进入等待队列 
		if(id<=n&&a[id].arrive_time==tim)
		{
			wait.push(a[id]);
			if(a[id].vip==1)
			ans_vip++;
			id++;
		}
		if(tim<21*3600)		
		{
			//先处理vip
			if(ans_vip>0)
			{
				for(int i=1;i<=m;i++)
				{
					if(server[i].size()>0)continue;
					if(wait.size()==0)continue;
					if(vip_table[i])
					{
						int len=wait.size();
						bool flag=false;
						//这里为单独把队列中的VIP提取出来,需要进行一次完整循环 
						for(int j=1;j<=len;j++)
						{
							Node t=wait.front();
							wait.pop();
							if(flag==false&&t.vip==1)
							{
								flag=true;
								t.server_time=tim;
								t.wait_time=t.server_time-t.arrive_time;
								server[i].push(t);
							}
							else
							{
								wait.push(t);
							}
						}	
					}	
				}	
			} 
			//没有vip情况(没有vip空闲桌子或者vip用户) 
			for(int i=1;i<=m;i++)//查看空的桌子 
			{
				if(server[i].size()>0)continue;//还在服务中 
				if(wait.size()==0)continue;//没有人 
				//正常桌子
				Node t=wait.front();
				wait.pop();
				t.server_time=tim;
				t.wait_time=t.server_time-t.arrive_time;
				server[i].push(t);	
			}
		}
		for(int i=1;i<=m;i++)
		{
			if(server[i].size()==0)continue;
			server[i].front().now_time--;
		}
	}
}
int main()
{
//	freopen("data.txt", "r", stdin);  
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int h,m,s;
		scanf("%d:%d:%d %d %d",&h,&m,&s,&a[i].now_time,&a[i].vip);
		a[i].arrive_time=h*3600+m*60+s;
		a[i].now_time*=60;
		if(a[i].now_time>2*3600)
		a[i].now_time=2*3600;
	}
	int k;
	cin>>m>>k;
	memset(vip_table,0,sizeof(vip_table));
	for(int i=1;i<=k;i++)
	{
		int x;
		cin>>x;
		vip_table[x]=true;
	}
	solve();
	sort(finish.begin(),finish.end(),cmp2);
	for(int i=0;i<finish.size();i++)
	{
		Node t=finish[i];
		Print(t.arrive_time);
		cout<<" ";
		Print(t.server_time);
		cout<<" ";
		int tim=t.wait_time/60;
		if(t.wait_time%60>=30)
		tim++;
		cout<<tim<<endl;
	}
	for(int i=1;i<m;i++)
	cout<<ans[i]<<" ";
	cout<<ans[m]<<endl;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值