PAT (Advenced Level) 1026. Table Tennis (30) 模拟排队,有vip

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
模拟排队,这次比前面题1017的情况要复杂得多.
维护一个顾客数组和一个桌子数组,具体数据结构见代码。
先按照到达时间的先后顺序对顾客进行排序。
处理的主体是顾客数组。每次找到最快能空出来的桌子,若同时空出来,选最小序号,若空出来的时间超过21点,则后续顾客不再处理。用桌子空出来的时间将顾客数组分成两段,前面一段表示此时已经到达俱乐部的顾客。若空出来的桌子是vip桌,寻找此时已到达俱乐部的vip,插队到队伍最前面(直接插入排序)。对队首顾客进行处理时,若该顾客是vip,且空出的桌子不是vip桌,则判断该vip顾客到达时是否有vip桌空出来,若有则选取最小序号的(这是一个坑)。剩下的就是注意每个顾客最多只能玩2个小时,还有注意输出等待时间时的四舍五入。
 
 
/*2015.7.22cyq*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
using namespace std;

//ifstream fin("case1.txt");
//#define cin fin

struct player{
	int arrive;		//到达时间
	int start;		//开始打球时间
	int process;	        //打球持续时间
	int leave;		//离开时间
	bool vip;		//是否vip顾客
	bool operator < (const player &a)const{//用于按到达时间排序
		return arrive<a.arrive;
	}
};
struct table{
	int time;//可以使用的时间,初始化为8点
	bool isVip;//是否为vip桌
	int count;//服务次数
	table():time(28800),isVip(false),count(0){}
};

int timeToInt(const string &s){
	int sum=0;
	sum+=(s[0]-'0')*10+s[1]-'0';
	sum=sum*60+(s[3]-'0')*10+s[4]-'0';
	sum=sum*60+(s[6]-'0')*10+s[7]-'0';
	return sum;
}
int main(){
	int N;
	cin>>N;
	vector<player> wait(N);
	string a;
	int b;
	for(int i=0;i<N;i++){
		cin>>a>>b>>wait[i].vip;
		wait[i].arrive=timeToInt(a);
		wait[i].process=b*60;
	}
	sort(wait.begin(),wait.end());//按照到达时间排序

	int K,M;
	cin>>K>>M;
	vector<table> tables(K+1);//0号不用
	int x;
	for(int i=0;i<M;i++){
		cin>>x;
		tables[x].isVip=true;
	}

	int quickTime;
	int quickTable;
	int index=0;  
	for(int i=0;i<N;i++){	//i号顾客
		quickTime=2147483647;
		for(int j=1;j<=K;j++){//最快结束的最小序号桌子
			if(tables[j].time<quickTime){
				quickTime=tables[j].time;
				quickTable=j;
			}
		}
		if(quickTime>=21*60*60||wait[i].arrive>=21*60*60){//超过21点
			wait.resize(i);
			break;
	    }	
		//以quickTime将队伍分成两段,前面一段此时在俱乐部内
		while(index<N&&wait[index].arrive<=quickTime)
			index++;
		if(tables[quickTable].isVip){//空出来的是vip桌子
			int vipPos=i;//标记此时俱乐部内队伍中最早来的vip位置
			for(int j=i;j<index;j++){
				if(wait[j].vip){
					vipPos=j;
					break;
				}
			}
			player tmp=wait[vipPos];
			for(int j=vipPos-1;j>=i;j--)
				wait[j+1]=wait[j];
			wait[i]=tmp;//vip插队到最前面
		}
		//对队首顾客进行处理
		if(wait[i].vip){//是个vip顾客
			if(!tables[quickTable].isVip){//空出的不是vip桌
				//寻找arrive时最小的vip桌
				for(int y=1;y<=K;y++){
					if(tables[y].isVip&&tables[y].time<=wait[i].arrive){
						quickTable=y;
						break;
					}
				}
			}
		}
		wait[i].start=max(tables[quickTable].time,wait[i].arrive);
		if(wait[i].process>7200)//大于两个小时
			wait[i].process=7200;
		wait[i].leave=wait[i].start+wait[i].process;
		tables[quickTable].time=wait[i].leave;
		tables[quickTable].count++;
	}
	for(auto it=wait.begin();it!=wait.end();it++){
		int t1=(*it).arrive;
		int t2=(*it).start;
		printf("%02d:%02d:%02d",t1/3600,t1%3600/60,t1%60);
		printf(" %02d:%02d:%02d",t2/3600,t2%3600/60,t2%60);
		printf(" %d\n",(t2-t1+30)/60);//四舍五入
	}
	cout<<tables[1].count;
	for(int i=2;i<=K;i++)
		cout<<" "<<tables[i].count;
	return 0;
}



                
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值