传送门:点击打开链接

题意:有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;
}