[PAT] A1026 Table Tennis

(繁)

题目大意

有若干乒乓球桌(编号1到N)和最多能玩2小时的玩家,若空闲则到达的人选择编号最小的乒乓球桌,若桌被占满了则排队。有VIP玩家和VIP球桌,若VIP球桌有空,则排在最前面的VIP玩家上桌,若没有VIP,则队首普通玩家上桌。轮到VIP玩家时,不是VIP桌也会上桌。8点到21点开业。
现给出每个人到达的时间、占桌时长(min)、是否VIP,以及桌子总数和VIP桌子数,VIP桌子编号。按照服务时间先后顺序输出每个人到达时间、得到服务时间、等待时长(以分钟单位取整),每桌服务人数。注意:如果这个人在得到服务时超过了21点,则不输出。

tips

1

e--计算结果 a--被除数 b--除数
1(四舍五入) : e=(a+(b/2))/b
2(进一法) : e=(a+(b-1))/b

2

vector容器的v.resize(int n,element)函数。
调整容器v大小为n;扩容后每个元素值为element,缺省为0。

测试点4

如果输入的时长超过2小时的,要手动缩短成2小时。

测试点5、7

当有多个桌子空闲时,且空闲的里面有vip桌时,vip用户会选择编号最小的vip桌,即使有空闲的、编号更小的普通桌。如果空闲的里面没有vip桌,vip用户选择编号最小的桌。

测试点8

超时,不知道为啥

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>///////
#include<iostream>
using namespace std;
#define N 10000
#define K 102
#define CLOSE 21 * 60 * 60
struct people {
	int arrive;
	int serve;
	int occupy;
	bool vip;
}player[N + 1];
int tend[K];//该桌子当前最早结束使用时间
int Ptable[K] = { 0 };//记录每张桌子服务人数
int ifserve[N + 1] = { 0 };//标记该客户是否被服务, 0未服务,负数判断将不会服务
vector<people>pans;
void fenpei(int ren, int zhuo) {
	player[ren].serve = tend[zhuo] < player[ren].arrive ? player[ren].arrive : tend[zhuo];
	if (player[ren].serve < CLOSE) {
		ifserve[ren] = 1;
		pans.push_back(player[ren]);
		tend[zhuo] = player[ren].serve + player[ren].occupy;
		Ptable[zhuo]++;
	}
}
//找到最早结束的桌子编号
int findmin(int a[], int k) {
	int min = 1;
	for (int i = 2;i <= k;i++) {
		if (a[i] < a[min])
			min = i;
	}
	return min;
}
//找到最早结束的VIP桌子编号
int findvipmin(int a[], int k, bool vip[]) {
	int time = CLOSE + 2 * 60 * 60 + 1;
	int min = -1;
	for (int i = 1;i <= k;i++) {
		if (vip[i] == 0)
			continue;
		if (a[i] < time) {
			min = i;
			time = a[i];
		}
	}
	return min;
}
bool cmp_arrive(people a, people b) {
	return a.arrive < b.arrive;
}
bool cmp_serve(people a, people b) {
	return a.serve < b.serve;
}
int main() {
	int n;
	int k;//桌子数
	int m;//vip桌子数
	bool VIPtable[K] = { 0 };//是否为VIP桌子
	int i, j;
	//输入 剔除到达时间>=21点的
	scanf("%d", &n);
	for (i = 0;i < n;i++) {
		int a, b, c;
		scanf("%d:%d:%d", &a, &b, &c);
		player[i].arrive = a * 60 * 60 + b * 60 + c;
		int temptime;
		scanf("%d%d", &temptime, &player[i].vip);
		player[i].occupy = temptime > 120 ? 120 * 60 : temptime * 60;
		if (player[i].arrive >= CLOSE) {
			i--;
			n--;
		}
		//player[i].wait = 0;
	}
	scanf("%d%d", &k, &m);
	for (i = 1;i <= k;i++)
		tend[i] = 8 * 60 * 60;
	for (i = 0;i < m;i++) {
		int temp;
		scanf("%d", &temp);
		VIPtable[temp] = 1;
	}

	sort(player, player + n, cmp_arrive);
	//计算服务时间
	for (i = 0;i < n;i++) {
		if (ifserve[i] != 0)continue;//过滤掉提前处理的VIP
		j = findmin(tend, k);//寻找最早结束编号最小的桌子
		if (tend[j] > CLOSE)break;
		//当第i个人来时,先判断是否是VIP
		if (player[i].vip) {//是VIP
			if (VIPtable[j]) fenpei(i, j); //桌是VIP桌,直接分配
			else {//桌非VIP
				if (tend[j] <= player[i].arrive) {//空桌不是VIP且人到时桌空,再找找有没有空VIP桌
					int u = findvipmin(tend, k, VIPtable);
					if (u > 0 && tend[u] <= player[i].arrive) {//若人到时VIP桌空,则分配
						fenpei(i, u);
					}
					else fenpei(i, j);
				}
				else fenpei(i, j);
			}
		}
		else {//队首不是VIP
			if (VIPtable[j] && tend[j] > player[i].arrive) {
				//桌是VIP桌且人要等,则看看后后面有没有VIP用户
				int v = i;
				for (;v < n;v++) {
					if (player[v].vip)break;
				}
				if (v == n) fenpei(i, j);//后面没VIP了,队首普通用户上桌
				else {
					fenpei(v, j);//否则VIP插队
					i--;//下一次循环还处理队首非VIP
				}
			}
			else fenpei(i, j);
		}
	}
	sort(pans.begin(), pans.end() , cmp_serve);
	for (i = 0;i < pans.size();i++) {
		int hh, mm, ss;
		hh = pans[i].arrive / 3600;
		mm = (pans[i].arrive - hh * 3600) / 60;
		ss = pans[i].arrive - hh * 3600 - mm * 60;
		printf("%02d:%02d:%02d ", hh, mm, ss);
		hh = pans[i].serve / 3600;
		mm = (pans[i].serve - hh * 3600) / 60;
		ss = pans[i].serve - hh * 3600 - mm * 60;
		printf("%02d:%02d:%02d ", hh, mm, ss);
		//printf("***%d*** ", player[i].vip);
		printf("%d
", (pans[i].serve - pans[i].arrive + 30) / 60);
	}
	for (i = 1;i <= k;i++) {
		if (i != 1)printf(" ");
		printf("%d", Ptable[i]);
	}
	return 0;
}

AC代码

参考了 (https://blog.csdn.net/a1552100455/article/details/100060101)

#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
using namespace std;
struct person {
	int come, get, play, wait;
	bool isvip = false;
}pperson;
struct table {
	bool isvip = false;
	int present = 8 * 3600;//当前该桌结束使用时间
	int num = 0;
};
vector<person> vec, res;//res存放被服务的人
vector<table> tables;//角标就是编号
//所有人中最早到的VIP脚标
int getVIP(int index) {
	index++;
	while (index < vec.size() && vec[index].isvip == false) index++;
	return index;
}
void alloac(int p, int t) {
	vec[p].get = tables[t].present < vec[p].come ? vec[p].come : tables[t].present;
	if (vec[p].get < 21 * 3600) {
		res.push_back(vec[p]);
		tables[t].num++;
		tables[t].present = vec[p].get + vec[p].play;
	}
}
bool cmp_come(person p1, person p2) {
	return p1.come < p2.come;
}
bool cmp_get(person p1, person p2) {
	return p1.get < p2.get;
}
int main() {
	int n, k, p;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		int hour, min, sec, play, flag;
		scanf("%d:%d:%d %d %d", &hour, &min, &sec, &play, &flag);
		pperson.come = hour * 3600 + min * 60 + sec;
		pperson.get = 21 * 3600;
		if (pperson.come >= 21 * 3600) continue;
		pperson.play = play > 120 ? 120 * 60 : play * 60;
		pperson.isvip = flag;
		vec.push_back(pperson);
	}
	scanf("%d %d", &k, &p);
	tables.resize(k + 1);
	for (int i = 0; i < p; i++) {
		int temp;
		scanf("%d", &temp);
		tables[temp].isvip = true;
	}
	sort(vec.begin(), vec.end(), cmp_come);
	int i = 0;
	int vipid = getVIP(-1);
	while (i < vec.size()) {
		int min = 999999999, index = -1;
		for (int j = 1; j < tables.size(); j++) {
			if (tables[j].present < min) {
				min = tables[j].present;
				index = j;
			}
		}//找最早结束的桌子index
		if (tables[index].present >= 21 * 3600) break;
		if (vec[i].isvip == true && i < vipid) {
			i++;
			continue;
		}
		if (tables[index].isvip == true) {//会员桌子
			//先检查会员 插队
			if (vec[i].isvip == true) {//队头就是会员
				alloac(i, index);
				vipid = getVIP(vipid);
				i++;
			}
			else {
				if (vipid < vec.size() && vec[vipid].come <= tables[index].present) {//看看队里有没有会员
					alloac(vipid, index);
					vipid = getVIP(vipid);
				}
				else {//没有会员
					alloac(i, index);
					i++;
				}
			}
		}
		else {//普通桌子
			int mintemp = 999999999; int tempindex = -1;
			if (vec[i].isvip == true) {//第一个人是VIP
				for (int k = 1; k < tables.size(); k++) {
					if (tables[k].isvip && tables[k].present < mintemp) {
						mintemp = tables[k].present;
						tempindex = k;
					}
				}
				if (tempindex != -1 && tables[tempindex].present <= vec[i].come) {//有会员桌子 插队
					alloac(i, tempindex);
					vipid = getVIP(vipid);
					i++;
				}
				else {//没有会员桌子 那就跟普通人一样
					alloac(i, index);
					vipid = getVIP(vipid);
					i++;
				}
			}
			else {//普通人
				alloac(i, index);
				i++;
			}
		}
	}
	sort(res.begin(), res.end(), cmp_get);
	for (int i = 0; i < res.size(); i++) {
		printf("%02d:%02d:%02d ", res[i].come / 3600, res[i].come % 3600 / 60, res[i].come % 60);
		printf("%02d:%02d:%02d %.0f
", res[i].get / 3600, res[i].get % 3600 / 60, res[i].get % 60, round((res[i].get - res[i].come) / 60.0));

	}
	printf("%d", tables[1].num);
	for (int i = 2; i < tables.size(); i++)
		printf(" %d", tables[i].num);
	return 0;
}

仔细比对了自己写的代码,比了好久都不知道复杂在了哪......如果有好心的大佬帮忙解答一下,感激不尽。
在我看来我们的区别是我是先看第一个人再看第一张桌,AC代码是先看桌再看人。

原文地址:https://www.cnblogs.com/yue36/p/12853644.html