POJ 3683 Priest John's Busiest Day 2-sat输出任意一组解
2016-10-19 16:45
525 查看
题目:
http://poj.org/problem?id=3683题意:
有一个牧师,要去主持婚礼,现在这一天有n场婚礼,每场婚礼都有一个时间段和持续时间,每场婚礼只能在其时间段的开端和末尾举行,问牧师能不能主持所有的婚礼,若能输出YES并输出每场婚礼举办的具体时间,否则输出NO思路:
每场婚礼时间段的开端和末尾看成点,然后判断任意两场婚礼的开端末尾是否冲突,冲突则建边,主要是判断区间的冲突问题总结:
这题不难,但让我纠结了好久,写的其中一份代码不知为何就是不对,但稍微改变输出方式就对了,好烦。。。对于第i场婚礼,i表示婚礼的开端,i+n表示婚礼的末尾,这份代码有点问题,第二份代码没问题
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int N = 2010; struct edge { int to, next; }g[N*N], g1[N*N]; struct node { int st, en; }arr[N*10]; int cnt, head , cnt1, head1 ; int num, idx, top, scc , st , dfn , low , pos , color , indeg ; bool vis ; int n; void add_edge(int v, int u) { g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++; } void add_edge1(int v, int u) { g1[cnt1].to = u, g1[cnt1].next = head1[v], head1[v] = cnt1++; } void init() { memset(head, -1, sizeof head); memset(dfn, -1, sizeof dfn); memset(vis, 0, sizeof vis); cnt = num = idx = top = 0; } void tarjan(int v) { dfn[v] = low[v] = ++idx; vis[v] = true, st[top++] = v; int u; for(int i = head[v]; i != -1; i = g[i].next) { u = g[i].to; if(dfn[u] == -1) { tarjan(u); low[v] = min(low[v], low[u]); } else if(vis[u]) low[v] = min(low[v], dfn[u]); } if(dfn[v] == low[v]) { num++; do { u = st[--top], vis[u] = false, scc[u] = num; }while(u != v); } } bool cmp(node a, node b) { if(a.en <= b.st || b.en <= a.st) return false; return true; } void toposort() { queue<int> que; for(int i = 1; i <= num; i++) if(indeg[i] == 0) que.push(i); while(! que.empty()) { int v = que.front(); que.pop(); if(color[v] == 0) color[v] = 1, color[pos[v]] = 2; for(int i = head1[v]; i != -1; i = g1[i].next) { int u = g1[i].to; if(--indeg[u] == 0) que.push(u); } } } bool solve() { for(int i = 1; i <= 2*n; i++) if(dfn[i] == -1) tarjan(i); for(int i = 1; i <= n; i++) { if(scc[i] == scc[i+n]) return false; pos[scc[i]] = scc[i+n], pos[scc[i+n]] = scc[i]; } cnt1 = 0; memset(head1, -1, sizeof head1); memset(indeg, 0, sizeof indeg); memset(color, 0, sizeof color); for(int i = 1; i <= 2*n; i++) for(int j = head[i]; j != -1; j = g[j].next) if(scc[i] != scc[g[j].to]) add_edge1(scc[g[j].to], scc[i]), indeg[scc[i]]++; toposort(); return true; } int main() { while(~ scanf("%d", &n)) { int a, b, c, d, e; init(); for(int i = 1; i <= n; i++) { scanf("%d:%d%d:%d%d", &a, &b, &c, &d, &e); arr[i].st = a*60 + b, arr[i].en = a*60 + b + e; arr[i+n].st = c*60 + d - e, arr[i+n].en = c*60 + d; } for(int i = 1; i <= n; i++) for(int j = i + 1; j <= n; j++) { if(cmp(arr[i], arr[j])) add_edge(i, j + n), add_edge(j, i + n); if(cmp(arr[i], arr[j+n])) add_edge(i, j), add_edge(j + n, i + n); if(cmp(arr[i+n], arr[j])) add_edge(i + n, j + n), add_edge(j, i); if(cmp(arr[i+n], arr[j+n])) add_edge(i + n, j), add_edge(j + n, i); } if(solve()) {//用不注释的这部分输出就错,用注释掉的部分输出就对,实在找不出哪里不对 printf("YES\n"); for(int i = 1; i <= 2*n; i++) if(color[scc[i]] == 1) printf("%02d:%02d %02d:%02d\n", arr[i].st/60, arr[i].st%60, arr[i].en/60, arr[i].en%60); // for(int i = 1; i <= n; i++) // if(color[scc[i]] == 1) // printf("%02d:%02d %02d:%02d\n", arr[i].st/60, arr[i].st%60, arr[i].en/60, arr[i].en%60); // else // printf("%02d:%02d %02d:%02d\n", arr[i+n].st/60, arr[i+n].st%60, arr[i+n].en/60, arr[i+n].en%60); } else printf("NO\n"); } return 0; }
另外一份代码,每场婚礼的开端末尾的点的编号是在一起的,这个就没问题
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int N = 2010; struct edge { int to, next; }g[N*N], g1[N*N]; struct node { int st, en; }arr[N*10]; int cnt, head , cnt1, head1 ; int num, idx, top, scc , st , dfn , low , pos , color , indeg ; bool vis ; int n; void add_edge(int v, int u) { g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++; } void add_edge1(int v, int u) { g1[cnt1].to = u, g1[cnt1].next = head1[v], head1[v] = cnt1++; } void init() { memset(head, -1, sizeof head); memset(dfn, -1, sizeof dfn); memset(vis, 0, sizeof vis); cnt = num = idx = top = 0; } bool cmp(node a, node b) { if(a.en <= b.st || b.en <= a.st) return false; return true; } void tarjan(int v) { dfn[v] = low[v] = ++idx; vis[v] = true, st[top++] = v; int u; for(int i = head[v]; i != -1; i = g[i].next) { u = g[i].to; if(dfn[u] == -1) { tarjan(u); low[v] = min(low[v], low[u]); } else if(vis[u]) low[v] = min(low[v], dfn[u]); } if(dfn[v] == low[v]) { num++; do { u = st[--top], vis[u] = false, scc[u] = num; }while(u != v); } } void toposort() { queue<int> que; for(int i = 1; i <= num; i++) if(indeg[i] == 0) que.push(i); while(! que.empty()) { int v = que.front(); que.pop(); if(color[v] == 0) color[v] = 1, color[pos[v]] = 2; for(int i = head1[v]; i != -1; i = g1[i].next) { int u = g1[i].to; if(--indeg[u] == 0) que.push(u); } } } bool solve() { for(int i = 0; i < 2*n; i++) if(dfn[i] == -1) tarjan(i); for(int i = 0; i < n; i++) { if(scc[2*i] == scc[2*i+1]) return false; pos[scc[2*i]] = scc[2*i+1], pos[scc[2*i+1]] = scc[2*i]; } cnt1 = 0; memset(head1, -1, sizeof head1); memset(indeg, 0, sizeof indeg); memset(color, 0, sizeof color); for(int i = 0; i < 2*n; i++) for(int j = head[i]; j != -1; j = g[j].next) if(scc[i] != scc[g[j].to]) add_edge1(scc[g[j].to], scc[i]), indeg[scc[i]]++; toposort(); return true; } int main() { while(~ scanf("%d", &n)) { int a, b, c, d, e; init(); for(int i = 0; i < n; i++) { scanf("%d:%d%d:%d%d", &a, &b, &c, &d, &e); arr[i*2].st = a*60 + b, arr[i*2].en = a*60 + b + e; arr[i*2+1].st = c*60 + d - e, arr[i*2+1].en = c*60 + d; } for(int i = 0; i < n; i++) for(int j = i + 1; j < n; j++) { if(cmp(arr[2*i], arr[2*j])) add_edge(2*i, 2*j+1), add_edge(2*j, 2*i+1); if(cmp(arr[2*i], arr[2*j+1])) add_edge(2*i, 2*j), add_edge(2*j+1, 2*i+1); if(cmp(arr[2*i+1], arr[2*j])) add_edge(2*i+1, 2*j+1), add_edge(2*j, 2*i); if(cmp(arr[2*i+1], arr[2*j+1])) add_edge(2*i+1, 2*j), add_edge(2*j+1, 2*i); } if(solve()) { printf("YES\n"); for(int i = 0; i < 2*n; i++) if(color[scc[i]] == 1) printf("%02d:%02d %02d:%02d\n", arr[i].st/60, arr[i].st%60, arr[i].en/60, arr[i].en%60); } else printf("NO\n"); } return 0; }
相关文章推荐
- [2-SAT 任意解 Tarjan 模板题] POJ 3683 Priest John's Busiest Day
- POJ 3683 Priest John's Busiest Day (2-SAT+输出可行解)
- POJ-3683-Priest John's Busiest Day(2-SAT染色)
- POJ 3683 Priest John's Busiest Day (2-SAT)
- Priest John's Busiest Day poj 3683 tarjan+2-SAT
- POJ 3683 Priest John's Busiest Day(2-SAT)
- poj 3683 Priest John's Busiest Day(2—sat)
- |poj 3683|2-SAT|Priest John's Busiest Day
- POJ 3683 Priest John's Busiest Day (2-SAT)
- 【POJ3683】Priest John's Busiest Day (2-sat输出任意解)
- poj - 3683 - Priest John's Busiest Day(2-SAT)
- POJ 3683 - Priest John's Busiest Day(2-SAT)
- poj 3683 Priest John's Busiest Day 2_sat
- POJ 3683 Priest John's Busiest Day(2-sat)
- [2-sat]POJ 3683——Priest John's Busiest Day
- POJ-3683 Priest John's Busiest Day(2-SAT问题)
- poj 3683 Priest John's Busiest Day
- POJ 3683 John's Busiest Day(2-SAT)
- POJ 3683. Priest John's Busiest Day
- POJ 3683 Priest John's Busiest Day