题目描述
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"。
- 每组数据末尾须打印额外的一行空行。
一些感受
这题我想到了思路,但是没能在规定的时间内写完。很多同学也没能把这道题按时完成,可见其难度是很大的。
不过,这个题数据规模较小,从算法的角度来说难度并不大,使用近乎穷举的方式就可以解决。
我认为,它难在了以下的几个方面。
- 题干很长,理解起来比较费时间,而且容易看起来很难。
- 输入复杂,且包含冗余信息。输入中用年月日时分秒来表示信息,而这样并不方便计算和比较;另外,描述任务信息的字符串对于解决本题是不必要的。
- 输出复杂,必须把时间转成MM/DD/YYYY hh:mm:ss的格式。
以后还是应该多练习类似的模拟题,锻炼题目快速分析的能力。
基本思路
时间格式的互换
为了更加方便的对时间点进行运算和比较,我们可以将其转换成时间戳的形式(可以以1800年1月1日00:00:00为起始时间),转换方式即找到每一项(年月日时分秒)与1800,1,1,0,0,0的差值,然后转化成秒并求和。
另外,我们还需要将时间点转化成输出所需的格式。过程与上面的转换相反,将时间戳转化成年月日时分秒,然后在1800,1,1,0,0,0的基础上加上这些值,从而得到时间戳对应的年月日时分秒,然后按规定格式输出即可。
解题思路
输入中可以获取所有人的所有任务涉及的时间段,我们可以用一个二维数组se来记录(第一维度记录不同的人,第二维度记录时间段)。
然后,我们可以使用所有这些任务时间段涉及的时间点将1800年1月1日00:00:00到2200年1月1日00:00:00这段时间分成若干小段。可以发现,每一小段时间要么包含在某个任务时间内,要么和这个任务时间没有交集。包含这个时间段的任务对应的人是无法在这段时间去开会的。
于是我们可以遍历所有这样的小段时间,可以统计每一小段时间缺席和可以开会的人数,从而找到合法(至少两人在场,最多一人缺席)的时间段。如果最长连续合法时间段长度大于1h,那么这段时间就满足了条件,可以将其输出。
需要注意的点
- 月和日的最小值均是1,而不是0。
- 本题中每个月都是30天。
- 时间戳可能会很大,为了防止溢出,应该使用long long而不是int。
- 任务时间段涉及的时间点可能会有重复。
完整代码
#include<iostream>
#include<set>
#include<iomanip>
#include<algorithm>
#define maxTS 12441600000
using namespace std;
struct Section{ //区间结构体
long long bg;
long long ed;
Section(long long b=0, long long e=0)
{
bg = b;
ed = e;
}
bool contain(const Section &se)
{
return bg <= se.bg && ed >= se.ed;
}
bool operator <(const Section &se) const
{
if(bg != se.bg) return bg < se.bg;
return ed < se.ed;
}
}se[25][150];
set<long long> S;
long long t[10000], tc;
int T, m, n[25];
int tsfm[6]={60,60,24,30,12};
long long timeStamp()
{
long long y, m, d, h, mi, s;
cin>>y>>m>>d>>h>>mi>>s;
return (((((y-1800)*12+(m-1))*30+(d-1))*24+h)*60+mi)*60+s;
}
void optT(long long t0)
{
int t1[6];
// 0 1 2 3 4 5
// s mi h d m y
for(int i=0;i<5;i++)
{
t1[i] = t0 % tsfm[i];
t0 /= tsfm[i];
}
t1[5]=t0;
cout<<setw(2)<<setfill('0')<<t1[4]+1<<"/";
cout<<setw(2)<<setfill('0')<<t1[3]+1<<"/";
cout<<setw(4)<<setfill('0')<<t1[5]+1800<<" ";
cout<<setw(2)<<setfill('0')<<t1[2]<<":";
cout<<setw(2)<<setfill('0')<<t1[1]<<":";
cout<<setw(2)<<setfill('0')<<t1[0];
}
bool check(const Section &ts)
{
int cnt = 0;
for(int i=0;i<m;i++)
{
bool absent = false;
for(int j=0;j<n[i];j++)
{
if(se[i][j].contain(ts))
{
absent=true;
break;
}
}
cnt += absent;
}
if(cnt <= 1 && (m-cnt) >= 2) return true;
return false;
}
bool meetT(int &i)
{
Section ts(-1,0);
for(;i<tc-1 && check(Section(t[i], t[i+1]));i++)
{
if(ts.bg == -1) ts.bg=t[i];
ts.ed = t[i+1];
}
if(ts.ed - ts.bg >= 3600)
{
cout<<"appointment possible from ";
optT(ts.bg);
cout<<" to ";
optT(ts.ed);
cout<<endl;
return true;
}
return false;
}
int main ()
{
ios::sync_with_stdio(false);
cin>>T;
for(int k=1;k<=T;k++)
{
{
S.clear();
tc=0;
S.insert(0);
t[tc++]=0;
}
cin>>m;
char info[105]; //存储无用信息
for(int i=0;i<m;i++)
{
cin>>n[i];
for(int j=0;j<n[i];j++)
{
se[i][j].bg = timeStamp();
se[i][j].ed = timeStamp();
if(S.find(se[i][j].bg) == S.end())
{
t[tc++] = se[i][j].bg;
S.insert(se[i][j].bg);
}
if(S.find(se[i][j].ed) == S.end())
{
t[tc++] = se[i][j].ed;
S.insert(se[i][j].ed);
}
cin.getline(info, 100);
}
}
sort(t, t+tc);
if(S.find(maxTS) ==S.end()) t[tc++] = maxTS;
int i=0;
bool flag=false;
cout<<"Scenario #"<<k<<":"<<endl;
for(int i=0;i<tc-1;i++) flag = meetT(i) || flag;
if (!flag) cout<<"no appointment possible"<<endl;
cout<<endl;
}
return 0;
}