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

解题思路:

这绝对是目前为止我遇到的坑点最多的问题,如果代码有问题,可以借用1026. Table Tennis (30)的测试样例进行修改。思路如下:

结构定义:

pair{int arrivetime,playtime,vip},分别代表该pair的到达时间、运动时长、是否是vip;

table{int num,leavetime,vip},分别代表球桌的使用次数统计、球桌空闲的最早时间,是否是vip球桌。

采用vector容器存储所有pair的信息,并按照到达时间升序排序,流程主要分为空闲球桌选择和pair选择两大步。

一、球桌选择:

  1. 如果队列第一位为非vip成员,那么就要找编号最小的空闲球桌。球桌编号从1至K,如果发现有球桌的leavetime小于等于队列第一位pair的到达时间,这说明当前有空闲球桌,可以直接选择。如果所有球桌都不符合条件,则说明当前没有空闲球桌,需要选择leavetime最小的球桌。
  2. 如果队列第一位为vip成员,那么就要找编号最小的空闲VIP球桌。同样遍历球桌信息,如果发现有vip球桌的leavetime小于等于队列首位成员的到达时间,则选择此vip球桌。如果没有满足条件的vip球桌,则找编号最小的空闲球桌。如果没有空闲球桌,就找leavetime最小的球桌(如果有并列,首先是vip球桌优先、其次是编号小球桌优先)。

二、队列成员选择

  1. 如果是非vip球桌,直接选择队列第一位成员。
  2. 如果是vip球桌,先遍历队列,寻找到达时间小于或等于球桌leavetime的最前vip成员,如果存在,选择该成员;如果不存在,选择队列第一位成员。

三、易错点分析

  1. 如果是vip成员,要优先找编号最小的空闲vip球桌,其次才是空闲的非vip球桌,最后是leavetime最小的非空闲球桌。
  2. 判断服务时间是够小于21:00:00的方法是球桌leavetime成员到达时间的最大值是否小于21:00:00
  3. 等待时间要四舍五入,不是向上取整。

AC代码:

测试点

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 0x7fffffff
struct pair1{
	int arrivetime,playtime,vip;
};
struct table{
	int num,leavetime,vip;
};
struct time{
	int h,m,s;
};
int swap2sec(char* a){
	int h=(a[0]-'0')*10+a[1]-'0';
	int min=(a[3]-'0')*10+a[4]-'0';
	int sec=(a[6]-'0')*10+a[7]-'0';
	return h*60*60+min*60+sec;	
}
struct time swap2hour(int sec){
	struct time t;
	t.s=sec%60;
	int min=sec/60;
	t.m=min%60;
	t.h=min/60;
	return t;
}
bool cmp(struct pair1 a,struct pair1 b){
	return a.arrivetime<b.arrivetime;	
}
int main(){
	vector<struct pair1> q;
	int i,N;
	cin>>N;
	getchar();
	for(i=0;i<N;i++){
		struct pair1 pp;
	 	char a[8];
		int p,tag;
		scanf("%s%d%d",a,&p,&tag);
		pp.arrivetime=swap2sec(a);
		if(p>120) 
			p=120;
		pp.playtime=60*p;
		pp.vip=tag;	
		q.push_back(pp);
	//	cout<<pp.arrivetime<<" "<<pp.playtime<<" "<<pp.vip<<endl;
	}
	sort(q.begin(),q.end(),cmp);
	struct table t[100];
	int K,M;
	cin>>K>>M;
	for(i=0;i<K;i++){
		t[i].leavetime=-INF;
		t[i].num=0;	
		t[i].vip=0;
	}
	for(i=0;i<M;i++){
		int num;
		scanf("%d",&num);
		t[num-1].vip=1;
	}
	for(i=0;i<N;i++){
		int j,mintable,mintime=INF,IsFound=0;
		//题目保证没有两对pair到达时间是一样的,但是可能存在多张空闲的球桌,队列第一位是vip,
		//要看有没有vip球桌(有多张vip桌子,要找编号最小的),没有再安排编号最小的桌子
		if(!q.front().vip){
			for(j=0;j<K;j++){
				if(t[j].leavetime<=q.front().arrivetime)	{
					mintable=j;
					break;
				}
				else {
					if(t[j].leavetime<mintime){
						mintime=t[j].leavetime;
						mintable=j;	
					}	
				}
			}	
		}
		else{
			for(j=0;j<K;j++){
				if(t[j].leavetime<=q.front().arrivetime&&t[j].vip)	{
					mintable=j;
					break;
				}
				else {
					if(t[j].leavetime<mintime){
						mintime=t[j].leavetime;
						mintable=j;	
					}	
				}
			}		
		}
		if(max(t[mintable].leavetime,q.front().arrivetime)>=21*60*60)//队列第一位到达时间和满足要球桌的离开时间的最大值大于20:59:59 
			break;
		t[mintable].num++;
		struct pair1 pt;
		if(!t[mintable].vip||q.front().arrivetime >= t[mintable].leavetime){
			pt=q.front();
			q.erase(q.begin());	
		}
		else{
			vector<struct pair1>::iterator tt;
			for(tt=q.begin();tt!=q.end();tt++){
				if((*tt).arrivetime>t[mintable].leavetime){
					tt=q.begin();
					break;	
				}
				else if((*tt).vip)
					break;	
			}
			if(tt==q.end()) //所有人都不是vip
				tt=q.begin(); 
			pt=*(tt);
			q.erase(tt);	
		}
		int servetime=max(t[mintable].leavetime,pt.arrivetime);
			servetime=max(servetime,8*60*60);//8点营业 
		t[mintable].leavetime=servetime+pt.playtime;
		int waittime=servetime-pt.arrivetime;
		int wait2min=waittime/60;
		if(waittime%60>=30)//四舍五入 
			wait2min++;
		struct time arr=swap2hour(pt.arrivetime);
		struct time serv=swap2hour(servetime);
	//	cout<<mintable<<" vip:"<<pt.vip<<" tablevip:"<<t[mintable].vip<<" table.leavetime:"<<t[mintable].leavetime<<" arrtime:"<<pt.arrivetime<<" ";
		printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",arr.h,arr.m,arr.s,serv.h,serv.m,serv.s,wait2min);
	}
	for(i=0;i<K-1;i++)
		printf("%d ",t[i].num);
	printf("%d\n",t[i].num);	
	return 0;	
} 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值