传送门:点击打开链接
题意:有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;
}