POJ 3683 Priest John's Busiest Day(2-SAT+方案輸出)
Time Limit: 2000MS | Memory Limit: 65536K | |||
Total Submissions: 10010 | Accepted: 3425 | Special Judge |
Description
John is the only priest in his town. September 1st is the John‘s busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of Love. This year N
Note that John can not be present at two weddings simultaneously.
Input
The first line contains a integer N ( 1 ≤ N ≤ 1000).
The next N
Output
The first line of output contains "YES" or "NO" indicating whether John can be present at every special ceremony. If it is "YES", output another N lines describing the staring time and finishing time of all the ceremonies.
Sample Input
2 08:00 09:00 30 08:15 09:00 20
Sample Output
YES 08:00 08:30 08:40 09:00
題目鏈接:POJ 3683
挑戰程序書上的例題,重新學習了一下2-SAT,一般的2-SAT是給出一些矛盾的條件,然後根據這些矛盾的條件用強連通分量算法來做。
首先要知道把什麽東西拆點,一般是去拆具有兩個對立面的事物,比如這題就是神父出現在開頭和神父出現在結尾,兩者就是不能同時發生的對立面,然後記這兩個對立面為$x_i$與$\lnot x_i$,顯然一般情況下如果a與b矛盾那麽就是說“a與b不能同時發生”,轉換成標記符號就是$\lnot (a \land b)$,然後把這個式子拆開得到$\lnot a\lor\lnot b$,那麽得到這樣一個析取範式,我們可以將他轉換成蘊含式子,即$(\lnot a \to b)\land(\lnot b \to a)$,這顯然可以轉換成兩條有向邊$<\lnot a, b>$與$<\lnot b, a>$,然後對圖進行DFS得到強連通分量,然後看$\lnot x_i$與$x_i$是否在同一個強連通分量裏,如果在同一個scc中顯然是矛盾的,這題的話就第i個時間段和第j個時間段的開頭和結束位置共4種關心進行判斷,沖突就按上面的方法連邊再scc處理即可,如果存在方案,只要判斷$x_i$所在的連通分量編號與$\lnot x_i$所在的連通分量編號即可
代碼:
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstdlib> #include <sstream> #include <numeric> #include <cstring> #include <bitset> #include <string> #include <deque> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 1010; const int MAXV = N * 2; const int MAXE = N * N * 4 * 2; struct edge { int to, nxt; edge() {} edge(int _to, int _nxt): to(_to), nxt(_nxt) {} }; edge E[MAXE]; int head[MAXV], tot; int dfn[MAXV], low[MAXV], belong[MAXV], st[MAXV], top, ts, ins[MAXV], sc; int s[N], t[N], d[N]; void init() { CLR(head, -1); tot = 0; CLR(dfn, 0); CLR(low, 0); top = sc = 0; CLR(ins, 0); sc = 0; } inline void add(int s, int t) { E[tot] = edge(t, head[s]); head[s] = tot++; } void Tarjan(int u) { low[u] = dfn[u] = ++ts; st[top++] = u; ins[u] = 1; for (int i = head[u]; ~i; i = E[i].nxt) { int v = E[i].to; if (!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if (ins[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { ++sc; int v; do { v = st[--top]; ins[v] = 0; belong[v] = sc; } while (u != v); } } int main(void) { int n, i, j; while (~scanf("%d", &n)) { init(); for (i = 1; i <= n; ++i) { int h1, m1, h2, m2; scanf(" %d:%d %d:%d %d", &h1, &m1, &h2, &m2, &d[i]); s[i] = h1 * 60 + m1; t[i] = h2 * 60 + m2; } for (i = 1; i <= n; ++i) //n*n*4*2 { for (j = 1; j <= n; ++j) { if (i == j) continue; if (min(s[i] + d[i], s[j] + d[j]) > max(s[i], s[j])) //s-s { add(i, j + n); add(j, i + n); } if (min(s[i] + d[i], t[j]) > max(s[i], t[j] - d[j])) //s-t { add(i, j); add(j + n, i + n); } if (min(t[i], s[j] + d[j]) > max(t[i] - d[i], s[j])) //t-s { add(i + n, j + n); add(j, i); } if (min(t[i], t[j]) > max(t[i] - d[i], t[j] - d[j])) //t-t { add(i + n, j); add(j + n, i); } } } for (i = 1; i <= (n << 1); ++i) if (!dfn[i]) Tarjan(i); int flag = 1; for (i = 1; i <= n; ++i) if (belong[i] == belong[i + n]) flag = 0; if (!flag) puts("NO"); else { puts("YES"); for (i = 1; i <= n; ++i) { if (belong[i] < belong[i + n]) printf("%02d:%02d %02d:%02d\n", s[i] / 60, s[i] % 60, (s[i] + d[i]) / 60, (s[i] + d[i]) % 60); else printf("%02d:%02d %02d:%02d\n", (t[i] - d[i]) / 60, (t[i] - d[i]) % 60, (t[i]) / 60, (t[i]) % 60); } } } return 0; }
POJ 3683 Priest John's Busiest Day(2-SAT+方案輸出)