传送门:点击打开链接
题意:有n个婚礼,有开始时间和结束时间,现在只有1个神父,必须要出现在每个婚礼的开始和结尾并持续一定的时间举行仪式。问神父是否可以做到对n个婚礼都矩形仪式。输出任意答案。
思路:这算是2SAT最经典的题了
首先说下2SAT,实质是把关系转换成了求强连通分量。如果已知a,必有b。那么就a->b这样连一条边。
一个点拆成2个点,分别表示true和false。
把边建好后,跑强连通分量,再去判断就行了。
做此类题目一定要把建边的关系理清楚,后面的问题就迎刃而解了。
#include <map> #include <set> #include <cmath> #include <ctime> #include <stack> #include <queue> #include <cstdio> #include <cctype> #include <bitset> #include <string> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #include <functional> #define fuck(x) cout<<"["<<x<<"]"; #define FIN freopen("input.txt","r",stdin); #define FOUT freopen("output.txt","w+",stdout); //#pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 2e3 + 5; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; struct Edge { int v, nxt; } E[MX * MX * 3]; int Head[MX][2], erear; void edge_init() { erear = 0; memset(Head, -1, sizeof(Head)); } void edge_add(int z, int u, int v) { E[erear].v = v; E[erear].nxt = Head[u][z]; Head[u][z] = erear++; } void edge_add(int u, int v) { edge_add(0, u, v); edge_add(1, v, u); } int Stack[MX], Belong[MX], vis[MX], ssz, bsz; void DFS(int u, int s) { vis[u] = 1; if(s) Belong[u] = s; for(int i = Head[u][s > 0]; ~i; i = E[i].nxt) { int v = E[i].v; if(!vis[v]) DFS(v, s); } if(!s) Stack[++ssz] = u; } void tarjan(int n) { ssz = bsz = 0; for(int i = 1; i <= n; i++) vis[i] = 0; for(int i = 1; i <= n; i++) { if(!vis[i]) DFS(i, 0); } for(int i = 1; i <= n; i++) vis[i] = 0; for(int i = ssz; i >= 1; i--) { if(!vis[Stack[i]]) DFS(Stack[i], ++bsz); } } int op[MX], ed[MX], dur[MX]; int get() { int h, i; scanf("%d:%d", &h, &i); return h * 60 + i; } void print(int x, char p) { int h = x / 60, i = x % 60; printf("%02d:%02d%c", h, i, p); } bool check(int l1, int r1, int l2, int r2) { if(r1 <= l2 || r2 <= l1) return false; return true; } int main() { int n; //FIN; while(~scanf("%d", &n)) { edge_init(); for(int i = 1; i <= n; i++) { op[i] = get(); ed[i] = get(); scanf("%d", &dur[i]); } for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) { if(check(op[i], op[i] + dur[i], op[j], op[j] + dur[j])) { edge_add(i, j + n); edge_add(j, i + n); } if(check(ed[i] - dur[i], ed[i], ed[j] - dur[j], ed[j])) { edge_add(i + n, j); edge_add(j + n, i); } if(check(op[i], op[i] + dur[i], ed[j] - dur[j], ed[j])) { edge_add(i, j); edge_add(j + n, i + n); } if(check(op[j], op[j] + dur[j], ed[i] - dur[i], ed[i])) { edge_add(j, i); edge_add(i + n, j + n); } } } tarjan(2 * n); bool ans = true; for(int i = 1; i <= n; i++) { if(Belong[i] == Belong[i + n]) { ans = false; break; } } if(!ans) printf("NO\n"); else { printf("YES\n"); for(int i = 1; i <= n; i++) { if(Belong[i] > Belong[i + n]) { print(op[i], ' '); print(op[i] + dur[i], '\n'); } else { print(ed[i] - dur[i], ' '); print(ed[i], '\n'); } } } } return 0; }