【模板】2-SAT 问题

【传送门】

分析

按照逻辑关系建图,跑tarjan,如果上下点在一个环中,说明不可能,不然就可能。

代码

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
#define N 2000005
struct edge {
    int to, nt;
}E[N << 1];
int dfn[N], low[N], H[N], S[N], belong[N];
bool vis[N];
int cnt, tot, top, scc, n, m;
void add_edge(int u, int v) {
    E[++ cnt] = (edge){v, H[u]}; 
    H[u] = cnt;
}
void tarjan(int u) {
    dfn[u] = low[u] = ++ tot;
    vis[u] = 1;
    S[top ++] = u;
    for (int e = H[u]; e; e = E[e].nt) {
        int v = E[e].to;
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (vis[v]) {
            low[u] = min(low[u], low[v]);
        }
    } 
    int j;
    if (dfn[u] == low[u]) {
        scc ++;
        do {
            j = S[-- top];
            belong[j] = scc;
            vis[j] = 0;
        }
        while (u != j);
    }
}
int main() {
    read(n); read(m);
    for (int i = 1; i <= m; i ++) {
        int u, v, a, b;
        read(u); read(a); read(v); read(b);
        add_edge(u + (a ^ 1) * n, v + b * n);
        add_edge(v + (b ^ 1) * n, u + a * n);
    }
    for (int i = 1; i <= 2 * n; i ++) {
        if (!dfn[i]) tarjan(i);
    }
    for (int i = 1; i <= n; i ++) {
        if (belong[i] == belong[i + n]) {
            printf("IMPOSSIBLE\n");
            return 0;
        }
    }
    printf("POSSIBLE\n");
    for (int i = 1; i <= n; i ++) {
        printf("%d ", belong[i] > belong[i + n]);
    }
    return 0;
}
posted @ 2019-03-15 14:09 chhokmah 阅读(...) 评论(...) 编辑 收藏