PAT A1026

题目:https://pintia.cn/problem-sets/994805342720868352/problems/994805472333250560

这个题,难的飞起。自己写出来只有一半对。里面逻辑特别复杂。

二刷这个题,有两点问题:

1.题目是假保证,要排除21点之后来的人。

2.没有单独开vector,而是直接在原数组上操作,然后用num记录人数,最后排序的时候可能忽略一种情况,即并不是排前num个人,因为有可能之后有vip已经抢先占桌了,所以break出去的时候num是小于真实的num的。所以刚开始进行初始化,然后排序把所有人一起排。

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = 1e9;
int n, k, m;
int st = 8 * 3600, ed = 21 * 3600, ivip = -1;
struct players{
	int t, st, p;
	bool v;
}temp;
struct tables{
	int t, num;
	bool v;
}table[110];
vector<players> player;
bool cmp1(players a, players b){
	return a.t < b.t;
}
bool cmp2(players a, players b){
	return a.st < b.st;
}
void nextvip(){
	ivip++;
	while(ivip <= player.size() && !player[ivip].v){
		ivip++;
	}
}
void give(int a, int b){
	if(player[a].t >= table[b].t){
		player[a].st = player[a].t;
	}
	else
		player[a].st = table[b].t;
	table[b].t = player[a].st + player[a].p;
	table[b].num++;
}
int main(){
	scanf("%d", &n);
	for(int i = 0; i < n; i++){
		int hh, mm, ss, pp, vip;
		scanf("%d:%d:%d %d %d", &hh, &mm, &ss, &pp, &vip);
		temp.t = hh * 3600 + mm * 60 + ss;
		temp.st = ed;
		if(temp.t >= ed)   //题目假保证
			continue;
		if(pp > 120)
			pp = 120;
		temp.p = pp * 60;
		temp.v = vip;
		player.push_back(temp);
	}
	sort(player.begin(), player.end(), cmp1);
	scanf("%d%d", &k, &m);
	for(int i = 1; i <= k; i++){
		table[i].t = st;
		table[i].num = 0;
		table[i].v = 0;
	}
	for(int i = 0; i < m; i++){
		int vip;
		scanf("%d", &vip);
		table[vip].v = 1;
	}
	nextvip();
	int i = 0;
	while(i < player.size()){
		int u = -1, MIN = INF;
		for(int j = 1; j <= k; j++){
			if(table[j].t < MIN){
				MIN = table[j].t;
				u = j;
			}
		}
		if(table[u].t >= ed)
			break;
		if(player[i].v && i < ivip){
			i++;
			continue;
		}
		if(table[u].v){
			if(player[i].v){
				give(i, u);
				if(i == ivip)
					nextvip();
				i++;
			}else{
				if(ivip < player.size() && player[ivip].t <= table[u].t){
					give(ivip, u);
					nextvip();
				}else{
					give(i, u);
					i++;
				}
			}
		}else{
			if(player[i].v){
				int v = -1, MIN = INF;
				for(int j = 1; j <= k; j++){
					if(table[j].v && table[j].t < MIN){
						MIN = table[j].t;
						v = j;
					}
				}
				if(v != -1 && player[i].t >= table[v].t)
					give(i, v);
				else
					give(i, u);
				if(i == ivip)
					nextvip();
				i++;
			}else{
				give(i, u);
				i++;
			}
		}
	}
	sort(player.begin(), player.end(), cmp2);
	for(int i = 0; i < player.size() && player[i].st < ed; i++){
		printf("%02d:%02d:%02d %02d:%02d:%02d %d\n", player[i].t/3600, player[i].t%3600/60, player[i].t%60, player[i].st/3600, player[i].st%3600/60, player[i].st%60, (player[i].st - player[i].t + 30)/60);
	}
	for(int i = 1; i <= k; i++){
		printf("%d", table[i].num);
		if(i < k)
			printf(" ");
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值