1026. Table Tennis (30)-PAT甲级真题(模拟)

4 篇文章 0 订阅

1026. Table Tennis (30)-PAT甲级真题(模拟)

【题目大意】
一个乒乓球俱乐部有N张桌子供公众使用。桌子的编号从1到n,对于任意一个玩家,如果他们到达时有一些桌子是空的,他们将被分配到桌号最小的桌。如果所有的桌子都被占满了,他们将排队等候。每个玩家最多玩两个小时。
【任务】

  1. 计算排队的每个人的等待时间
  2. 计算每个桌子当天服务的玩家数量。

【难点】让这个程序有点复杂的一点是,加入等待队列的特殊情况考虑—VIP

  1. 当有贵宾桌空闲时,队列中的第一个VIP有特权使用它。
  2. 如果队列中没有VIP,第一个普通玩家玩家可以使用。
  3. 如果有VIP桌空闲,但是等待队列中只有普通玩家,普通玩家正常使用,桌子分配依据仍然是桌号最小的先分配

解题思路

  1. 不追求代码的极度简洁追求逻辑清晰,该题可用面向对象思路,建立玩家player和桌子table的结构体
  2. 对玩家依次进行分析:是否有空闲桌,如果有空闲桌,根据玩家的属性进行计算得到当前的桌号//如果没有空闲桌判断后续等待队列中是否有vip玩家进行抢先
  3. 判断是否有空闲桌:将该玩家的到达时间依次与桌子的最迟可玩时间进行比较,达到时间晚于某桌的最迟可玩时间,则该桌对于该玩家是空闲的
  4. 判断等待队列中是否有vip玩家抢先:(1)记录最早结束游戏的vip桌的桌号/结束时间(2)从该普通顾客之后查看是否有在此结束时间早到的第一位vip顾客(3)找到该vip顾客,对该顾客结构体的信息进行赋值
  5. 避免玩家的重复计算:设置visited,如果访问过,就设置为true,遍历时直接跳过

【个人正在锻炼刷题,记录日常,代码未简化,keep learing】

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;

struct player {
	string s_arriveTime, s_beginTime;
	int t_arriving = 0, t_begin, playtime, tag, waitTime;
	bool visited = false;
	bool operator<(const player& p)const {
		return t_arriving < p.t_arriving;
	}
};
struct table {
	int index, num_server = 0, tag = 0, at_least_time = 0;
};
/*	将游戏桌按结束当前游戏的时间进行升序排序  */
bool cmp1(const table& t1, const table& t2) {
	return t1.at_least_time < t2.at_least_time;
}
/*	将游戏桌按桌号升序排序  */
bool cmp2(const table& t1, const table& t2) {
	return t1.index < t2.index;
}
/*	将玩家按照开始游戏的时间升序排序  */
bool cmp3(const player& p1, const player& p2) {
	return p1.t_begin < p2.t_begin;
}
/*	空的vip桌优先,空桌都按序号从小到大排序  */
bool cmp4(const table& t1, const table& t2) {
	if (t1.tag == t2.tag)return t1.index < t2.index;
	return t1.tag > t2.tag;
}
vector<player>playList;
vector<player>waitlist;
vector<table>tableList;

int convert_to_time(string t) {
	int h, m, s;
	h = stoi(t.substr(0, 2).c_str());
	m = stoi(t.substr(3, 2).c_str());
	s = stoi(t.substr(6, 2).c_str());
	return s + 60 * m + 3600 * h;
}
/* 有多个空位:号码小的桌优先;只有一个空位:直接上;没有空位返回-1*/
int avaible_table_number(player myplayer) {
	vector<table>avaibleList;
	//查看空桌
	for (int i = 0; i < tableList.size(); i++) {
		if (tableList[i].at_least_time < myplayer.t_arriving) {
			avaibleList.push_back(tableList[i]);
		}
	}
	if (avaibleList.size() != 0) {
		if (myplayer.tag == 1) {
			sort(avaibleList.begin(), avaibleList.end(), cmp4);
		}
		else {
			sort(avaibleList.begin(), avaibleList.end(), cmp2);
		}
		return avaibleList[0].index;
	}
	return -1;
}
//查找被vip捷足先登的vip桌号
int avaible_vip_table(int customerNum, int arraveTime) {
	int num_table = 1, time_last = INT_MAX;
	//记录最早结束游戏的vip桌的桌号/结束时间
	for (int i = 0; i < tableList.size(); i++) {
		if (tableList[i].tag == 1 && tableList[i].at_least_time < time_last) {
			num_table = i + 1;
			time_last = tableList[i].at_least_time;
		}
	}
	//从该普通顾客之后查看是否有在此结束时间早到的第一位vip顾客
	if (customerNum >= playList.size())return -1;
	for (int i = customerNum; i < playList.size() && playList[i].t_arriving < time_last; i++) {
		if (playList[i].tag == 1 && playList[i].visited == false) {
			//找到该vip顾客,对该顾客信息进行赋值
			playList[i].waitTime = (time_last - playList[i].t_arriving + 30) / 60;		//顾客等待的时间
			playList[i].visited = true;
			playList[i].t_begin = time_last;
			tableList[num_table - 1].at_least_time = playList[i].t_begin + playList[i].playtime * 60;
			tableList[num_table - 1].num_server++;
			return num_table;
		}
	}
	return -1;
}

int main() {
	int n, k, m;
	cin >> n;
	for (int i = 0; i < n; i++) {
		player p;
		cin >> p.s_arriveTime >> p.playtime >> p.tag;
		p.playtime = p.playtime > 120 ? 120 : p.playtime;
		p.t_arriving = convert_to_time(p.s_arriveTime);
		if (p.t_arriving < 28800 || p.t_arriving >= 75600)continue;
		playList.push_back(p);
	}
	sort(playList.begin(), playList.end(), less<player>());
	cin >> k >> m;
	//构造k个桌子
	for (int i = 0; i < k; i++) {
		table mytable;
		mytable.index = i + 1;
		tableList.push_back(mytable);
	}
	//赋值m个vip桌
	for (int i = 0; i < m; i++) {
		cin >> k;
		tableList[k - 1].tag = 1;
	}
	//进行游戏
	for (int i = 0; i < playList.size(); i++) {
		if (playList[i].visited)continue;
		else {
			playList[i].visited = true;
		}
		//判断当前是否有空桌
		int tableNumber = avaible_table_number(playList[i]);
		if (tableNumber != -1) {
			playList[i].t_begin = playList[i].t_arriving;												//游戏结束时间	
			if (playList[i].t_begin >= 75600)continue;													//如果他开始的时间关店了,则跳过这个循环
			playList[i].waitTime = 0;																	//等待时间
			tableList[tableNumber - 1].at_least_time = playList[i].t_begin + playList[i].playtime * 60; //该桌下次接客的最早时间
			tableList[tableNumber - 1].num_server++;													//该桌接客数+1
		}
		else {
			//2.客人来的时候并没有空桌,则进入等待队列,等待结束的条件:在最先结束游戏的桌之前没有vip空桌和vip顾客插队
			if (playList[i].tag == 1 || avaible_vip_table(i + 1, playList[i].t_arriving) == -1) {
				//如果没有vip顾客,则慢慢等待最早结束开始的桌
				int num_table = 1, time_last = INT_MAX;
				for (int i = 0; i < tableList.size(); i++) {
					if (tableList[i].at_least_time < time_last) {
						num_table = i + 1;
						time_last = tableList[i].at_least_time;
					}
				}

				playList[i].waitTime = (time_last - playList[i].t_arriving + 30) / 60;			//顾客等待的时间
				playList[i].t_begin = time_last;												//顾客游戏结束时间
				if (time_last >= 75600)continue;												//如果他开始的时间关店了,则跳过这个循环
				tableList[num_table - 1].at_least_time = time_last + playList[i].playtime * 60;	//该桌下次接客的最早时间
				tableList[num_table - 1].num_server++;											//该桌接客数+1
			}
			else {	//位子被人抢了 重新进行评判
				playList[i].visited = false;
				i--;
			}
		}
	}
	sort(playList.begin(), playList.end(), cmp3);
	for (int i = 0; i < playList.size(); i++) {
		if (playList[i].t_begin > 75600)continue;
		int hour = playList[i].t_begin / 3600;
		int minute = playList[i].t_begin % 3600 / 60;
		int second = playList[i].t_begin % 60;
		string s_hour = (hour > 9 ? "" : "0") + to_string(hour);
		string s_minute = (minute > 9 ? "" : "0") + to_string(minute);
		string s_second = (second > 9 ? "" : "0") + to_string(second);
		playList[i].s_beginTime = s_hour + ":" + s_minute + ":" + s_second;
		cout << playList[i].s_arriveTime << " " << playList[i].s_beginTime << " " << playList[i].waitTime << endl;
	}
	cout << tableList[0].num_server;
	for (int i = 1; i < tableList.size(); i++) {
		cout << " " << tableList[i].num_server;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值