2-SAT

https://www.luogu.com.cn/problem/P4782

\(n\) 个布尔变量和 \(m\) 条约束,每条约束形如 \(a\lor b\),其中 \(a,b\) 是布尔方程,给每个布尔变量赋值使得所有约束成立.

把每个布尔变量拆成两个点,分别表示取 \(0\) 和取 \(1\),然后把约束条件翻译成图论语言.

因为 \(a\lor b \Leftrightarrow (\neg a \to b)\land(\neg b \to a)\),连 \(\neg a \to b\)\(\neg b \to a\) 的边即可.

特别的,如果出现 \(a\land b\) 的约束,这相当于直接要求 \(a\)\(b\) 为真,连 \(\neg a \to a\)\(\neg b \to b\) 的边即可.

在构成有向图中,使用 \(tarjan\) 算法找 \(SCC\),如果某个布尔变量的两个点属于同一 \(SCC\),说明约束是不可能成立的,否则令拓扑序更大的变量元为真即可. 实际上,\(tarjan\) 算法求出的 \(SCC\) 为逆拓扑序.

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;


void solve(){
    int n,m;
    cin >> n >> m;

    int N = 2*n;
    vector<vector<int>> adj(N+1);
    for (int t=0;t<m;t++){
        int i,a,j,b;
        cin >> i >> a >> j >> b;
        adj[i+(a^1?n:0)].push_back(j+(b?n:0));
        adj[j+(b^1?n:0)].push_back(i+(a?n:0));
    }

    vector<int> dfn(N+1),low(N+1),belong(N+1);
    vector<bool> in_stk(N+1,false);
    stack<int> stk;
    int tot = 1;
    int timer = 1;

    function<void(int)> dfs = [&](int u){
        dfn[u] = low[u] = timer++;
        in_stk[u] = true;
        stk.push(u);

        for (auto& v:adj[u]){
            if (dfn[v]==0){
                dfs(v);
                low[u] = min(low[u],low[v]);
            }
            else if (in_stk[v]){
                low[u] = min(low[u],dfn[v]);
            }
        }

        if (dfn[u]==low[u]){
            while (1){
                int cur = stk.top();
                stk.pop();
                in_stk[cur] = false;
                belong[cur] = tot;

                if (cur==u) break;
            }          
            tot++;
        }
    };
    for (int i=1;i<=N;i++){
        if (dfn[i]==0) dfs(i);
    }

    vector<int> res(n+1);
    for (int i=1;i<=n;i++){
        if (belong[i]==belong[i+n]){
            cout << "IMPOSSIBLE" << '\n';
            return;
        }

        if (belong[i]<belong[i+n]){
            res[i] = 0;  
        }
        else{
            res[i] = 1;
        }
    }

    cout << "POSSIBLE" << '\n';
    for (int i=1;i<=n;i++){
        cout << res[i] << ' ';
    }
    cout << '\n';
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    // cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-08-08 13:24  kzssCCC  阅读(6)  评论(0)    收藏  举报