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