WEEK10团队聚会

B - 团 队 聚 会

题目描述
TA团队每周都会有很多任务,有的可以单独完成,有的则需要所有人聚到一起,开过会之后才能去做。但TA团队的每个成员都有各自的事情,找到所有人都有空的时间段并不是一件容易的事情。

给出每位助教的各项事情的时间表,你的任务是找出所有可以用来开会的时间段。

输入格式 第一行一个数T(T≤100),表示数据组数。

对于每组数据,第一行一个数m(2 ≤ m ≤ 20),表示TA的数量。

对于每位TA,首先是一个数n(0≤ n≤100),表示该TA的任务数。接下来n行,表示各个任务的信息,格式如下

YYYY MM DD hh mm ss YYYY MM DD hh mm ss “some string here”

每一行描述的信息为:开始时间的年、月、日、时、分、秒;结束时间的年、月、日、时、分、秒,以及一些字符串,描述任务的信息。

数据约定:

所有的数据信息均为固定位数,位数不足的在在前面补前导0,数据之间由空格隔开。

描述信息的字符串中间可能包含空格,且总长度不超过100。

所有的日期时间均在1800年1月1日00:00:00到2200年1月1日00:00:00之间。

为了简化问题,我们假定所有的月份(甚至2月)均是30天的,数据保证不含有不合法的日期。

注意每件事务的结束时间点也即是该成员可以开始参与开会的时间点。

输出格式 对于每一组数据,首先输出一行"Scenario #i:",i即表明是第i组数据。

接下来对于所有可以用来开会的时间段,每一个时间段输出一行。

需要满足如下规则:

在该时间段的任何时间点,都应该有至少两人在场。 在该时间段的任何时间点,至多有一位成员缺席。 该时间段的时间长度至少应该1h。
所有的成员都乐意一天24h进行工作。

举个例子,假如现在TA团队有3位成员,TT、zjm、hrz。

那么这样的时间段是合法的:会议开始之初只有TT和zjm,后来hrz加入了,hrz加入之后TT离开了,此后直到会议结束,hrz和zjm一直在场。

要求:

输出满足条件的所有的时间段,尽管某一段可能有400年那么长。 时间点的格式为MM/DD/YYYY hh:mm:ss。
时间段的输出格式为"appointment possible from T0 to T1",其中T0和T1均应满足时间点的格式。
严格按照格式进行匹配,如果长度不够则在前面补前导0。 按时间的先后顺序输出各个时间段。 如果没有合适的时间段,输出一行"no
appointment possible"。 每组数据末尾须打印额外的一行空行。
思路:构建时间类,包含年月日小时分钟秒,实现符号重载start_用于存储每个成员的事务的起始时间,end_用于存储每个成员事务的结束时间,t用于存储所有时间点初始包含了时间范围边界点。
初始化变量,输入每个成员事务的时间点,直接忽略描述信息
对t中所有时间点升序排序后,从最左侧开始进行与滑动窗口类似的操作确定空闲时间段
首先确定使空闲时间段最长的右边界,要求时间点位于空闲时间,此时间点有空的人数至少2人且最多缺席一人
确定好右边界后,就确定了一段空闲时间段(初始左边界是最左侧,之后每轮的左边界由上一轮确定),判断该时间段是否满足一个小时,满足则输出该时间段。
之后确定下一轮时间段的左边界,方法与确定右边界时类似。
重复之前的操作持续向右滑动窗口
用一个标记记录是否有输出符合要求的空闲时间段,最后如果没有则输出相应信息

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
using namespace std;
struct time {
	int year, month, day, hour, minute, second;
	time() {}
	time(int y, int mo, int d, int h, int mi, int s) {
		year = y, month = mo, day = d, hour = h, minute = mi, second = s;
	}
	bool operator < (const time& b)const
	{
		if (year != b.year)return year < b.year;
		if (month != b.month)return month < b.month;
		if (day != b.day)return day < b.day;
		if (hour != b.hour)return hour < b.hour;
		if (minute != b.minute)return minute < b.minute;
		return second < b.second;
	}
	bool operator > (const time& b)const { return b < *this; }
	bool operator <= (const time& b)const { return !(b < *this); }
	bool operator == (const time& b)const { return !(b < *this || *this < b); 
	}
}start_[25][120], end_[25][120], t[4020];
int T, num[25], cnt, n;
time tbegin(1800, 1, 1, 0, 0, 0), tend(2200, 1, 1, 0, 0, 0);
int label = 0;
void output(int i) {
	if (t[i].month < 10)printf("0");
	printf("%d/", t[i].month);
	if (t[i].day < 10)printf("0");
	printf("%d/", t[i].day);
	printf("%d ", t[i].year);
	if (t[i].hour < 10)printf("0");
	printf("%d:", t[i].hour);
	if (t[i].minute < 10)printf("0");
	printf("%d:", t[i].minute);
	if (t[i].second < 10)printf("0");
	printf("%d", t[i].second);

}
bool rightbound(int index) {
	if (index == 0)return 0;
	int tot = 0;
	for (int i = 1; i <= n; i++) {
		if (num[i] == 0) { tot++; continue; }

		if (t[index] <= start_[i][1] && t[index] > tbegin) { tot++; continue; }

		if (t[index] > end_[i][num[i]]) { tot++; continue; }
		if (t[index] == end_[i][num[i]])continue;
		for (int j = 1; j <= num[i]; j++) {
			if (t[index] > start_[i][j] && t[index] <= end_[i][j])break;
			if (j + 1 <= num[i] && t[index] > end_[i][j] && t[index] <= start_[i][j + 1]) { tot++; break; }
		}
	}
	//至少两个人在场以及最多一人缺席
	if (tot >= 2 && tot >= n - 1)return 1;
	else return 0;
}
//确定空闲段的左边界
bool leftbound(int index) {
	if (index == cnt)return 0;
	int tot = 0;
	for (int i = 1; i <= n; i++){
		if (num[i] == 0) { tot++; continue; }
		if (t[index] < start_[i][1]) { tot++; continue; }
		if (end_[i][num[i]] <= t[index] && tend > t[index]) { tot++; continue; }
		for (int j = 1; j <= num[i]; j++) {
			if (start_[i][j] <= t[index] && end_[i][j] > t[index])break;
			if (j + 1 <= num[i] && end_[i][j] <= t[index] && start_[i][j + 1] > t[index]) { tot++; break; }
		}
	}
	if (tot >= 2 && tot >= n - 1)return 1;
	else return 0;
}

//满足小时长
bool isanhour(int left, int right) {
	time l = t[left], r = t[right];
	if (r.year - l.year >= 2)return 1;
	r.month += (r.year - l.year) * 12;
	if (r.month - l.month >= 2)return 1;
	r.day += (r.month - l.month) * 30;
	if (r.day - l.day >= 2)return 1;
	r.hour += (r.day - l.day) * 24;
	if (r.hour - l.hour >= 2)return 1;
	r.minute += (r.hour - l.hour) * 60;
	r.second += (r.minute - l.minute) * 60;
	if (r.second - l.second >= 3600)return 1;
	return 0;
}

void judge(int left, int right) {
	if (!isanhour(left, right))return;
	label = 1;
	printf("appointment possible from ");
	output(left);
	printf(" to ");
	output(right);
	printf("\n");
}
int main()
{
	cin.sync_with_stdio(false);
	cin >> T;
	for (int cc = 1; cc <= T; cc++) {
		memset(num, 0, sizeof(num));
		memset(start_, 0, sizeof(start_));
		memset(end_, 0, sizeof(end_));
		memset(t, 0, sizeof(t));
		cnt = 0;
		label = 0;
		t[++cnt] = tbegin;
		t[++cnt] = tend;
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> num[i];
			for (int j = 1; j <= num[i]; j++) {
				cin >> start_[i][j].year >> start_[i][j].month >> start_[i][j].day >> start_[i][j].hour >> start_[i][j].minute >> start_[i][j].second;
				cin >> end_[i][j].year >> end_[i][j].month >> end_[i][j].day >> end_[i][j].hour >> end_[i][j].minute >> end_[i][j].second;
				t[++cnt] = start_[i][j];
				t[++cnt] = end_[i][j];
				string meiyong;
				getline(cin, meiyong);
			}
		}
		sort(t + 1, t + 1 + cnt);
		printf("Scenario #%d:\n", cc);
		int left = 1, right = 1;
		while (left <= cnt && right <= cnt) {
			right++;
			if (right > cnt)break;
			//找到使时间段最长的右边界
			while (right <= cnt && rightbound(right))right++;
			right--;
			judge(left, right);
			left = right + 1;
			//确定左边界
			while (left <= cnt && !leftbound(left))left++;
			right = left;
		}
		if (label == 0)printf("no appointment possible\n");
		printf("\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值