POJ 3683 Priest John‘s Busiest Day
题意:给定几个时间,si, ti, di每一个时间要选[si, si + di]或[ti - di, ti],问是否能选出全部时间不相交的方案
思路:显然的2-sat,注意推断相交的方法
代码:
#include <cstdio> #include <cstring> #include <vector> using namespace std; const int N = 1005; int n; vector<int> g[2 * N]; bool mark[2 * N]; void init() { memset(mark, false, sizeof(mark)); for (int i = 0; i < 2 * n; i++) g[i].clear(); } void add_edge(int u, int x, int v, int y) { g[(2 * u + x)^1].push_back(2 * v + y); g[(2 * v + y)^1].push_back(2 * u + x); } int s[N], e[N], d[N]; int S[2 * N], sn; bool dfs(int u) { if (mark[u^1]) return false; if (mark[u]) return true; mark[u] = true; S[sn++] = u; for (int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if (!dfs(v)) return false; } return true; } bool judge(int s1, int e1, int s2, int e2) { if (s1 >= s2 && s1 < e2) return true; if (s2 >= s1 && s2 < e1) return true; return false; } bool solve() { init(); for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { int s1, e1, s2, e2; if (x == 0) { s1 = s[i]; e1 = s[i] + d[i]; } else { s1 = e[i] - d[i]; e1 = e[i]; } if (y == 0) { s2 = s[j]; e2 = s[j] + d[j]; } else { s2 = e[j] - d[j]; e2 = e[j]; } if (s1 > e1 || s2 > e2) return false; if (judge(s1, e1, s2, e2)) add_edge(i, !x, j, !y); } } } } for (int i = 0; i < n * 2; i += 2) { if (!mark[i] && !mark[i + 1]) { sn = 0; if (!dfs(i + 1)) { for (int j = 0; j < sn; j++) mark[S[j]] = false; sn = 0; if (!dfs(i)) return false; } } } return true; } int main() { while (~scanf("%d", &n)) { int h1, m1, h2, m2; for (int i = 0; i < n; i++) { scanf("%d:%d%d:%d%d", &h1, &m1, &h2, &m2, &d[i]); s[i] = h1 * 60 + m1; e[i] = h2 * 60 + m2; } if (!solve()) printf("NO\n"); else { printf("YES\n"); for (int i = 0; i < n; i++) { int st, et; if (mark[i * 2]) { st = s[i]; et = s[i] + d[i]; } else { st = e[i] - d[i]; et = e[i]; } printf("%02d:%02d %02d:%02d\n", st / 60, st % 60, et / 60, et % 60); } } } return 0; }