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;
}