PAT 1026. Table Tennis (30) 队列模拟与特殊情况处理

/*************************
题意:
有一堆台球桌,和一堆赶来排队的人
每当有一个台球桌开放,队头的人就去使用
如果此时有一个VIP桌开放
队中的VIP可以马上使用,不用理会队伍里的其他人。
计算入队时间、开始时间、等待时间
并计算每个桌子服务的人数。
/************************
求解要点和注意点:
实现思路:
先把所有顾客按到达时间排序
接着分成vip队列和普通队列,都插进去。
然后每次选出一个空余时间最早的台球桌
如果有一个VIP桌的空余时间也是最早,同时这个桌子不会被普通顾客抢占
则我们选择这个VIP桌,而不是序号小的普通桌
接着再判断我们应该选择普通人还是VIP人来玩这个桌子
并计算这个桌子下一次的空余时间

坑点:
1.每个人最多玩2个小时,即使他们想玩更久也不行。
2.开放时间为8:00到21:00,  21:00以及21:00之后场馆的球桌不再接收新的人来玩。
注意是21:00及之后不能开新局,但21:00之前开的局是没事的。
3.顾客的进场时间可以刚好是21:00.
3.★当某一刻,同时开放了普通桌1和VIP桌3,而队伍中又正好有VIP
	则VIP会直接选择3号桌而不是1号桌。
4.等待时间是四舍五入而不是向上取整。
************************/

/***********************
笔记:

*********************/
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define M 10010
#define INF 0x7fffffff
struct player{
	int h,m,s,begint;
	int ut;
	bool operator<(player b)const  {  
        return begint > b.begint;
    }  
};
int fvip[105];
int main(){
	int n,i,h,m,s,k,ut,vip;
	priority_queue<struct player> q, vipq;
	scanf("%d",&n);
	struct player p;
	for(i=0;i<n;i++){
		scanf("%d:%d:%d%d%d",&h,&m,&s,&ut,&vip);
		if(ut>120)
			ut = 120;
		p.h=h;p.m=m;p.s=s;p.ut=ut*60;
		p.begint=h * 3600 + m * 60 + s;
		if(vip){
			vipq.push(p);
		}
		else q.push(p);
	}
	int vipn;
	scanf("%d%d",&k,&vipn);
	memset(fvip,0,sizeof(fvip));
	int vipi;
	for(i=0;i<vipn;i++){
		scanf("%d",&vipi);
		fvip[vipi]=1;
	}

	int tmin,select;
	int outt[105],ans[105];
	for(i=1;i<=k+1;i++){
		outt[i]=8*3600;
		ans[i]=0;
	}

	int waitt;
	while( !(q.empty()&&vipq.empty()) ){
		tmin = INF;
		for(i = 1;i <=k; i++){
			if(outt[i] < tmin){
				tmin=outt[i];
				select=i;
			}else if(outt[i] == tmin)
				if((!vipq.empty() ) && (vipq.top().begint<tmin || q.empty() || vipq.top().begint < q.top().begint) &&
						(!fvip[select]) && fvip[i] ){
					select = i;
				}
		}

		//选q和vipq中最小的那个
		if(q.empty()){p=vipq.top();vipq.pop();}
		else if(vipq.empty()) {p=q.top();q.pop();}
		else if(fvip[select] && vipq.top().begint <= tmin){
			p=vipq.top();vipq.pop();
		}
		else if(q.top().begint < vipq.top().begint) {
			p=q.top();q.pop();
		}
		else {
			p=vipq.top();vipq.pop();
		}

		if( tmin > p.begint){
			waitt=tmin-p.begint;
			outt[select] = tmin + p.ut;
		}
		else{
			waitt=0;
			tmin = p.begint;
			outt[select] = p.begint + p.ut;
		}

		if(tmin >= 21*3600)
			break;
		ans[select]++;
		printf("%02d:%02d:%02d ",p.h,p.m,p.s);
		printf("%02d:%02d:%02d ",tmin/3600,(tmin/60)%60,tmin%60);
		waitt = waitt/60 +(waitt%60<30?0:1);
		printf("%d\n",waitt);
	}
	for(i=1;i<=k;i++){
		if(i != k)
			printf("%d ",ans[i]);
		else printf("%d\n",ans[i]);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值