题意:约翰是区里唯一的神父。有N对新人在同一天结婚,每个婚礼有一个特殊仪式,要有神父参加,时间为Si ~ Si + Di 或者 Ti - Di ~ Ti, 神父只能同时参加一个,问能否合理安排时间使神父参加所有婚礼
思路:由于每个婚礼只有开始和结束两个时间段,选择了一个就不能选择另外一个,这样的话转换为布尔公式就好做了,就转为2 - SAT问题。再进行强连通分量分解,就能得到答案了。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
const int maxn = 2 * 1e3 + 10;
using namespace std;
struct time {
int h, m;
time() {}
time(int h, int m) : h(h), m(m) {}
void input() { scanf("%d:%d", &h, &m); }
void output() { printf("%02d:%02d", h, m); }
bool operator < (time t) const {
if(t.h != h) return h < t.h;
return m < t.m;
}
bool operator >= (time t) const {
if(t.h != h) return h > t.h;
return m >= t.m;
}
time nxt(int t) {
int now = h * 60 + m + t;
int hh = now / 60, mm = now % 60;
return time(hh, mm);
}
};
time st[maxn], ed[maxn];
time st1[maxn], ed1[maxn];
vector<int> G[maxn], rG[maxn], vs;
int n, topo[maxn], use[maxn], tal;
void add(int f, int t) {
G[f].push_back(t);
rG[t].push_back(f);
}
void dfs(int u) {
use[u] = 1;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!use[v]) dfs(v);
}
vs.push_back(u);
}
void rdfs(int u, int k) {
use[u] = 1; topo[u] = k;
for(int i = 0; i < rG[u].size(); i++) {
int v = rG[u][i];
if(!use[v]) rdfs(v, k);
}
}
int scc() {
int k = 1;
memset(use, 0, sizeof(use));
for(int i = 1; i <= 2 * n; i++) {
if(!use[i]) dfs(i);
}
memset(use, 0, sizeof(use));
for(int i = vs.size() - 1; i >= 0; i--) {
int v = vs[i];
if(!use[v]) rdfs(v, k++);
}
return k - 1;
}
int main() {
while(scanf("%d", &n) != EOF) {
vs.clear();
for(int i = 0; i < maxn; i++) {
G[i].clear();
rG[i].clear();
}
for(int i = 1; i <= n; i++) {
st[i].input();
ed[i].input();
scanf("%d", &tal);
st1[i] = st[i].nxt(tal);
ed1[i] = ed[i].nxt(-tal);
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(i == j) continue;
if(st[i] >= st[j] && st[i] < st1[j]) {
add(i, j + n); add(j, i + n);
}
if(st[i] >= ed1[j] && st[i] < ed[j]) {
add(i, j); add(j + n, i + n);
}
if(ed1[i] >= st[j] && ed1[i] < st1[j]) {
add(i + n, j + n); add(j, i);
}
if(ed1[i] >= ed1[j] && ed1[i] < ed[j]) {
add(i + n, j); add(j + n, i);
}
}
}
scc();
int sign = 1;
for(int i = 1; i <= n; i++) {
if(topo[i] == topo[i + n]) {
sign = 0; break;
}
}
if(!sign) { printf("NO\n"); continue; }
printf("YES\n");
for(int i = 1; i <= n; i++) {
if(topo[i] > topo[i + n]) {
st[i].output(); printf(" ");
st1[i].output(); printf("\n");
} else {
ed1[i].output(); printf(" ");
ed[i].output(); printf("\n");
}
}
}
return 0;
}