题目链接:POJ-3683 Priest John's Busiest Day
题意
$n$对新人要举行婚礼,每个婚礼有各自的开始时间$S_i$和结束时间$T_i$,还要举行一个时长为$D_i$的仪式,这个仪式只能在$S_i$或$T_i-D_i$时刻开始,问如何安排每个婚礼举行仪式的时间,让一个神父能够主持每个婚礼的仪式。
思路
把每个婚礼看成一个集合,两个可以举行仪式的时间段是集合里的两个元素。不同集合的时间段可能会有冲突,我们要从每个集合里选出一个时间段,令选出的$n$个时间段两两不冲突,这就是一个2-SAT求任意可行方案问题。
2-SAT入门:传送门
代码实现
#include <iostream> #include <cstdio> #include <cstring> using std::min; using std::max; const int N = 2010, M = N * N; struct Edge { int to, nex; } edge[M]; int num_e; int head[N]; int dfn[N], low[N], scc[N], sz[N], idx, tot; bool insta[N]; int sta[N], top; int S[N], T[N], D[N]; void init() { num_e = 0, top = 0, idx = 0, tot = 0; memset(head, 0, sizeof(head)); memset(insta, 0, sizeof(insta)); memset(scc, 0, sizeof(scc)); memset(dfn, 0, sizeof(dfn)); } void add_edge(int x, int y) { edge[++num_e].to = y; edge[num_e].nex = head[x]; head[x] = num_e; } void tarjan(int u) { dfn[u] = low[u] = ++idx; sta[++top] = u; insta[u] = true; for (int i = head[u]; i; i = edge[i].nex) { int v = edge[i].to; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (insta[v]) low[u] = min(low[u], dfn[v]); } if (dfn[u] == low[u]) { ++tot; do { scc[sta[top]] = tot; sz[tot]++; insta[sta[top]] = false; } while (sta[top--] != u); } } void solve(int n) { for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (min(S[i] + D[i], S[j] + D[j]) > max(S[i], S[j])) { add_edge(i, j + n); add_edge(j, i + n); } if (min(S[i] + D[i], T[j]) > max(S[i], T[j] - D[j])) { add_edge(i, j); add_edge(j + n, i + n); } if (min(T[i], S[j] + D[j]) > max(T[i] - D[i], S[j])) { add_edge(i + n, j + n); add_edge(j, i); } if (min(T[i], T[j]) > max(T[i] - D[i], T[j] - D[j])) { add_edge(i + n, j); add_edge(j + n, i); } } } for (int i = 0; i < 2 * n; i++) { if (!dfn[i]) tarjan(i); } for (int i = 0; i < n; i++) { if (scc[i] == scc[i+n]) { puts("NO"); return ; } } puts("YES"); for (int i = 0; i < n; i++) { if (scc[i] < scc[i+n]) printf("%02d:%02d %02d:%02d ", S[i] / 60, S[i] % 60, (S[i] + D[i]) / 60, (S[i] + D[i]) % 60); else printf("%02d:%02d %02d:%02d ", (T[i] - D[i]) / 60, (T[i] - D[i]) % 60, T[i] / 60, T[i] % 60); } } int main() { int n; while (~scanf("%d", &n)) { init(); for (int i = 0, h1, h2, m1, m2; i < n; i++) { scanf("%02d:%02d %02d:%02d %d", &h1, &m1, &h2, &m2, &D[i]); S[i] = h1 * 60 + m1; T[i] = h2 * 60 + m2; } solve(n); } return 0; }