题意:
有n对新人打算在同一天举行结婚仪式,只有一个神父。
第i对新人的结婚仪式时间为 sti 到 edi,在其仪式开始或者结束时,需要进行一个用时为di的特别仪式。
即 si 到 si + di,或者 edi - di 到 edi,这两个时间段,该时间段需要神父在场。
判断是否可以通过合理安排每个特别仪式在开始或者结束矩形,使得神父能够出席所有特殊仪式。
解析:
挑战程序设计竞赛P326.
代码:
#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cassert>
#include <iostream>
#include <algorithm>
#define pb push_back
#define mp make_pair
#define LL long long
#define lson lo,mi,rt<<1
#define rson mi+1,hi,rt<<1|1
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a,b) memset(a,b,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
using namespace std;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double ee = exp(1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 2e3 + 10; // v << 1
const double pi = acos(-1.0);
const LL iinf = 0x3f3f3f3f3f3f3f3f;
int readT()
{
char c;
int ret = 0,flg = 0;
while(c = getchar(), (c < '0' || c > '9') && c != '-');
if(c == '-') flg = 1; else ret = c ^ 48;
while( c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c ^ 48);
return flg ? - ret : ret;
}
int V; //顶点数
vector<int> g[maxn]; //图的邻接表
vector<int> rg[maxn]; //把边反向后的图
vector<int> vs; //后续遍历顺序的顶点列表
bool used[maxn]; //访问标记
int cmp[maxn]; //所属强连通分量的拓扑序 即入度大连通分量的在后
void init()
{
for (int i = 0; i <= V; i++)
{
g[i].clear();
rg[i].clear();
}
}
void addEdge(int fr, int to)
{
g[fr].pb(to);
rg[to].pb(fr);
}
//正向dfs
void dfs(int v)
{
used[v] = true;
int sz = g[v].size();
for (int i = 0; i < sz; i++)
{
if (!used[g[v][i]])
{
dfs(g[v][i]);
}
}
vs.pb(v);
}
//反向dfs
void rdfs(int v, int k)
{
used[v] = true;
cmp[v] = k;
int sz = rg[v].size();
for (int i = 0; i < sz; i++)
{
if (!used[rg[v][i]])
{
rdfs(rg[v][i], k);
}
}
}
//返回强连通分量个数
int scc()
{
mem0(used);
vs.clear();
for (int v = 0; v < V; v++)
{
if (!used[v])
{
dfs(v);
}
}
mem0(used);
int k = 0;
int sz = vs.size();
for (int i = sz - 1; i >= 0; i--)
{
if (!used[vs[i]])
{
rdfs(vs[i], k++);
}
}
return k;
}
int n;
int st[maxn], ed[maxn];
int d[maxn];
void solve()
{
// 0 ~ n - 1 : xi
// n ~ 2 * n - 1 : !xi
V = n << 1;
init();
for (int i = 0; i < n; i++)
{
for (int j = 0; j < i; j++)
{
//i j 都在开头举办 冲突
// xi -> !xj , xj -> !xi
if (Min(st[i] + d[i], st[j] + d[j]) > Max(st[i], st[j]))
{
addEdge(i, n + j);
addEdge(j, n + i);
}
//i开头举办 j结尾举办 冲突
// xi -> xj , !xj -> !xi
if (Min(st[i] + d[i], ed[j]) > Max(st[i], ed[j] - d[j]))
{
addEdge(i, j);
addEdge(n + j, n + i);
}
//i结尾举办 j开头举办 冲突
// !xi -> !xj, xj -> xi
if (Min(st[j] + d[j], ed[i]) > Max(st[j], ed[i] - d[i]))
{
addEdge(n + i, n + j);
addEdge(j, i);
}
//i j 结尾举办 冲突
// !xi -> xj , !xj -> xi
if (Min(ed[i], ed[j]) > Max(ed[i] - d[i], ed[j] - d[j]))
{
addEdge(n + i, j);
addEdge(n + j, i);
}
}
}
scc();
for (int i = 0; i < n; i++)
{
if (cmp[i] == cmp[n + i])
{
puts("NO");
return;
}
}
puts("YES");
for (int i = 0; i < n; i++)
{
if (cmp[i] > cmp[n + i])
{
//xi为真 在开头举办
printf("%02d:%02d %02d:%02d\n", st[i] / 60, st[i] % 60, (st[i] + d[i]) / 60, (st[i] + d[i]) % 60);
}
else
{
//xi为假 在结尾举办
printf("%02d:%02d %02d:%02d\n", (ed[i] - d[i]) / 60, (ed[i] - d[i]) % 60, ed[i] / 60, ed[i] % 60);
}
}
}
int main()
{
#ifdef LOCAL
FIN;
#endif // LOCAL
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
{
int hour, minute;
scanf("%d:%d", &hour, &minute);
st[i] = hour * 60 + minute;
scanf("%d:%d", &hour, &minute);
ed[i] = hour * 60 + minute;
scanf("%d", &d[i]);
// printf("%02d:%02d %02d:%02d\n", st[i] / 60, st[i] % 60, ed[i] / 60, ed[i] % 60);
}
solve();
}
return 0;
}