PAT A 1026. Table Tennis (30)

题目

A table tennis club has N tables available to the public. The tables arenumbered from 1 to N. For any pair of players, if there are some tables openwhen they arrive, they will be assigned to the available table with thesmallest number. If all the tables are occupied, they will have to wait in aqueue. 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 foreach table the number of players it has served for the day.

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

Input Specification:

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

Output Specification:

For each test case, first print the arriving time, serving time and thewaiting time for each pair of players in the format shown by the sample. Thenprint in a line the number of players served by each table. Notice that theoutput must be listed in chronological order of the serving time. The waitingtime must be rounded up to an integer minute(s). If one cannot get a tablebefore 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

 

题目很长,比较坑

1、题目没讲清楚,如果VIP在排队,且到达队首时,如果同时有VIP桌和普通桌,VIP会去id最小的VIP桌而不是id最小的普通桌。

2、题目说假定没有玩家会玩超过2个小时,没说是保证不会有,也不说该怎么处理。但测试却有超过2小时的,需要强制结束。

3、题目说保证玩家在时间段内到达,但实际却有不在时间段内的玩家。

4、注意点:进位指4舍5入


代码:

东改西改,改得一塌糊涂了……

#include <iostream>
#include <queue>
#include <deque>
#include <algorithm>
using namespace std;

const int MAX=0x0fffffff;	//最大数

struct player	//玩家结构
{
	int time;		//到达时间
	int t_time;		//获得桌子时间
	int g_time;		//打球时间
	int vip;		//是否为vip
};

player get_pair();	//获取一队玩家信息
bool cm(const player &p1,const player &p2);		//根据到达时间对玩家排序
void Form_put(int i);			//按格式输出,补0
void Put_time(int t);			//按格式输出时间
void Print_time(player p,int t);	//输出玩家的时间信息
bool Is_vip(const player &p);	//判断玩家是否是VIP,用于find_if

int main()
{
	int n,k,m,i,j;
	deque<player> players;	//存储所有玩家
	cin>>n;
	for(i=0;i<n;i++)
		players.push_back(get_pair());
	sort(players.begin(),players.end(),cm);	//按时间排序

	queue<player> table[100];	//桌子(……可以不用队列)
	int vip[100]={0};		//标记桌子是否为VIP桌(从0开始编号,对应1号桌)
	int count_t[100]={0};	//用于统计每个桌子的使用次数(从0开始编号)
	int has_vip_tb;		//统计是否有可用VIP桌,MAX表示没有,i代表对应的第一个VIP桌的编号(从0开始编号)
	cin>>k>>m;			//输入VIP信息
	for(i=0;i<m;i++)
	{
		cin>>j;
		vip[j-1]=1;
	}

	int time=8*3600;	//时间,初始化为8:00
	int last_time;		//有人桌最早的结束时间
	int f_time;			//队列中最早到的时间(仅在有空桌的时候有效)
	player tempp;		//临时玩家结构
	deque<player>::iterator fvip;	//指出队列中第一个VIP的为为位置
	
	while(!players.empty()&&time<21*3600)	//还有玩家且时间在21:00前
	{
		last_time=MAX;	//最早结束的桌的时间初始化为最大
		f_time=MAX;		//最早到的人的时间(仅在有空桌子时)
		has_vip_tb=MAX;	//初始化vip桌可用标签
		fvip=find_if(players.begin(),players.end(),Is_vip);		//寻找队列中的第一个VIP
		for(i=0;i<k;i++)	//寻找最早结束时间
		{
			if(!table[i].empty())
			{
				if(table[i].front().t_time+table[i].front().g_time<last_time)
					last_time=table[i].front().t_time+table[i].front().g_time;
			}
			else	//有空桌时计算最早到的人
			{
				f_time=players.front().time;
				if(f_time<time)	//!!!限制以防来的人比8点还早(包括比对应时间早)
					f_time=time;
			}
		}
		if(last_time<=f_time)	//在最早结束的桌结束前没有人来
			time=last_time;	
		else		//在最早结束桌前有人
			time=f_time;
		if(time>=21*3600)	//最早时间到达结束时间,跳出
			break;
		if(fvip<players.end()&&(*fvip).time<=time)	//队伍中有VIP,或VIP最早到,!!!单独处理
		{
			for(i=0;i<k;i++)	//!!!找编号最小的可用VIP桌
			{
				if(table[i].empty()&&vip[i]==1)
				{
					has_vip_tb=i;
					break;
				}
				if(!table[i].empty()&&vip[i]==1
					&&table[i].front().t_time+table[i].front().g_time==time)
				{
					has_vip_tb=i;
					table[i].pop();
					break;
				}
			}
			if(has_vip_tb!=MAX)	//找到了,则处理
			{
				tempp=(*fvip);
				tempp.t_time=time;
				table[has_vip_tb].push(tempp);
				players.erase(fvip);
				Print_time(tempp,time);
				count_t[has_vip_tb]++;
				if(players.empty())
					break;
				continue;	//!!!跳出,可能还有VIP和VIP桌需要特殊处理
			}
		}
		for(i=0;i<k;i++)	//按序号扫描各桌
		{
			if(!table[i].empty())	//对有玩家的桌子考虑是否在该时刻前结束
			{
				if(table[i].front().t_time+table[i].front().g_time==time)	//在该时刻结束
				{
					table[i].pop();
					if(players.front().time<=time)	//非VIP且有人在排队
					{
						tempp=players.front();
						players.pop_front();
						tempp.t_time=time;
						table[i].push(tempp);
						Print_time(tempp,time);
						count_t[i]++;
						if(players.empty())
							break;
					}
				}
			}
			else if(players.front().time<=time)	//是空桌(即有空桌),且该时刻前有玩家到
			{
				tempp=players.front();
				players.pop_front();
				tempp.t_time=time;
				table[i].push(tempp);
				Print_time(tempp,time);
				count_t[i]++;
				if(players.empty())
					break;
			}
		}
	}
	cout<<count_t[0];
	for(i=1;i<k;i++)
		cout<<" "<<count_t[i];

	return 0;
}

player get_pair()	//输入一对玩家信息
{
	int h,m,s;
	player p;
	cin>>h;
	cin.get();
	cin>>m;
	cin.get();
	cin>>s;
	p.time=h*3600+m*60+s;
	cin>>p.g_time>>p.vip;
	if(p.g_time>120)	//!!!限制玩家的最长时间为2小时
		p.g_time=120;
	p.g_time*=60;
	return p;
}

bool cm(const player &p1,const player &p2)	//比较到达时间
{
	return p1.time<p2.time;
}

void Form_put(int i)	//补0
{
	if(i<10)
		cout<<0;
	cout<<i;
}

void Put_time(int t)	//输出时间
{
	Form_put(t/3600);
	cout<<":";
	t%=3600;
	Form_put(t/60);
	cout<<":";
	t%=60;
	Form_put(t);
}

void Print_time(const player p,int t)	//输出玩家的时间
{
	int dtime;
	Put_time(p.time);
	cout<<" ";
	if(t<p.time)
	{
		Put_time(p.time);
		dtime=0;
	}
	else
	{
		Put_time(t);
		dtime=(t-p.time)/60;
		if((t-p.time)%60>=30)
			dtime++;
	}
	cout<<" "<<dtime<<endl;
}

bool Is_vip(const player &p)	//判断是否是vip
{
	return p.vip;
}


 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值