http://poj.org/problem?id=3683 /*题目描述:有n个婚礼,每个婚礼有起始时间si,结束时间ti,还有一个主持时间ti,ti必须安排在婚礼的开始 或者结束,主持由祭祀来做,但是只有一个祭祀,所以各个婚礼的主持时间不能重复, 问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案: 即每个婚礼的主持时间段是什么样的。*/ /* 对于题意:主持时间要么在开始的时刻,要么在结束的时刻,而且各个婚礼之间有限制,因此用2-sat 建图:对于婚礼i和婚礼j,i表示开始主持,i`表示结束主持,j也是一样 枚举每一对不同的i和j, 如果i和j冲突,连接ij` 如果i和j`冲突,连接ij 如果i`和j冲突,连接i`j` 如果i`和j冲突,连接i`j */ #include<stdio.h> #include<string.h> #define MAXN 10000 #define MAXM 1000000 struct Edge//建图时用的 { int from, to, next; }edge[MAXM]; struct E { int from, to, next; }e[MAXM]; struct Time { int from, to, len; }p[MAXN]; int n, cnt, head[MAXN], head2[MAXN], cnt2;//建图时用到的变量 int index, scc, dfn[MAXN], low[MAXN], belong[MAXN], num[MAXN];//tarjan算法用到的变量 int out[MAXN], in[MAXN], top, stack[MAXN]; bool instack[MAXN], ans[MAXN]; char s1[9], s2[9]; int opp[MAXN]; void addedge(int u, int v)//建图 { edge[cnt].from = u; edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void addedge2(int u, int v) { e[cnt2].from = u; e[cnt2].to = v; e[cnt2].next = head2[u]; head2[u] = cnt2++; } int cal(char str[])//时间转换 { int temp = 0; temp = str[0] - '0'; temp *= 10; temp += str[1] - '0'; temp *= 60; temp += ((str[3] - '0') * 10 + (str[4] - '0')); return temp; } bool judge(int f1, int l1, int f2, int l2)//判断是否冲突 { if(f2 < f1 + l1 && f1 < f2 + l2) return true; return false; } int min(int a, int b) { if(a<b) return a; else return b; } void tarjan(int u)//强连通分支算法 { int i, v; dfn[u] = low[u] = ++index; stack[++top] = u; instack[u] = true; for(i = head[u]; i!=-1; i = edge[i].next) { v = edge[i].to; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v]) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { scc++;//强连通分支数量 while(1) { v = stack[top--]; instack[v] = false; belong[v] = scc; num[scc]++; if(u == v) break; } } } int q[MAXM], col[MAXN]; bool solve() { int i; // int q[MAXM], col[MAXN]; //tarjan index = scc = top = 0; memset(instack, 0, sizeof(instack)); memset(dfn, 0, sizeof(dfn)); memset(num, 0, sizeof(num)); for(i=0; i < 2*n; i++) if(!dfn[i]) tarjan(i); for(i=0; i<n; i++) { if(belong[i] == belong[i+n]) return false; opp[belong[i]] = belong[i+n]; opp[belong[i+n]] = belong[i]; } //topsort cnt2 = 0; memset(in, 0, sizeof(in)); memset(head2, -1, sizeof(head2)); memset(col, 0, sizeof(col)); for(i=0; i < cnt; i++) if(belong[edge[i].from] != belong[edge[i].to]) { addedge2(belong[edge[i].to], belong[edge[i].from]); in[belong[edge[i].from]]++; } int l = 0, r = 0; for(i=0; i<scc; i++) if(in[i]==0) q[r++] = i; while(l<r) { int u = q[l++]; if(col[u] == 0) { col[u] = 1; col[opp[u]] = -1; } int id = head2[u]; while(id!=-1) { if(--in[e[id].to] == 0) q[r++] = e[id].to; id = e[id].next; } } memset(ans, 0, sizeof(ans)); for(i=0; i<n; i++) if(col[belong[i]] == 1) ans[i] = 1; return true; } void output(int t) { printf("%02d:%02d", t/60, t%60); } int main() { // freopen("in.txt", "r", stdin); int i, j; while(scanf("%d", &n) != EOF) { memset(head, -1, sizeof(head)); cnt = 0; for(i=0; i<n; i++) { int len; scanf("%s%s%d", s1, s2, &len); p[i].from = cal(s1); p[i].to = cal(s2); p[i].len = len; } for(i=0; i<n; i++) { for(j=0; j<n; j++) { if(i==j) continue; if(judge(p[i].from, p[i].len, p[j].from, p[j].len)) addedge(i, j+n); if(judge(p[i].from, p[i].len, p[j].to - p[j].len, p[j].len)) addedge(i, j); if(judge(p[i].to - p[i].len, p[i].len, p[j].from, p[j].len)) addedge(i+n, j+n); if(judge(p[i].to - p[i].len, p[i].len, p[j].to - p[j].len, p[j].len)) addedge(i+n, j); } } if(solve()) { printf("YES/n"); for(i=0; i<n; i++) { if(ans[i]) { output(p[i].from); printf(" "); output(p[i].from + p[i].len); printf("/n"); } else { output(p[i].to - p[i].len); printf(" "); output(p[i].to); printf("/n"); } } } else printf("NO/n"); } return 0; }