2‐SAT (By Rami) - YessineJallouli/Competitive-Programming GitHub Wiki

#include <bits/stdc++.h>

// 0-indexed

using namespace std;
using vi = vector<int>;
using vvi = vector<vi>;
using vb = vector<bool>;

struct Sat2 {
    int n, d;
    vvi adj, rev;

    explicit Sat2(int _d) : n(2 * _d), adj(n), rev(n), d(_d)
    {
    }

    void topoSort(int r, vi &L, vb &vis)
    {
        if (!vis[r])
        {
            vis[r] = true;
            for (auto s: adj[r]) topoSort(s, L, vis);
            L.push_back(r);
        }
    }


    vi topoSort() {
        vb vis(n);
        vi L;
        for (int i = 0; i < n; i++) topoSort(i, L, vis);
        std::reverse(L.begin(), L.end());
        return L;
    }

    // Decomposition of strongly connected components
    struct SCDec {
        int components; // Number of components
        vi componentId; // A map that gives the id of the strongly connected component of a node
        vi topologicalOrder; // A topological order of the components
    };

    void assign(int u, vb &assigned,vi & cmpId,int id)
    {
        if (assigned[u]) return;
        cmpId[u]=id;
        assigned[u] = true;
        for (int v : rev[u]) assign(v,assigned,cmpId,id);
    }

    SCDec getSCComponents()
    {
        vi topoOrder = topoSort(),cmpId(n);
        vb hasId(n);
        int components=0;
        for (auto i :topoOrder) if (!hasId[i]) assign(i,hasId,cmpId,components++);
        return {components,cmpId, topoOrder};
    }

    // Get a solution, or an empty vector if not satisfiable (the most important one)
    vb satisfy()
    {
        vb vis(2 * d), sol(d), assigned(d);
        auto &&[components,cmpId, topoOrder] = getSCComponents();
        vi topoIndex(2*d);
        vb cmpAssigned(components);
        for (int i = 0; i < n; i += 2) {
            if (cmpId[i] == cmpId[i^1]) return {};
            sol[i / 2] = cmpId[i] > cmpId[i^1];
        }
        return sol;
    }

    // Connect two nodes in a graph
    void connect(int a, int b, bool r1, bool r2)
    {
        adj[2*a^r1].push_back(2*b^r2);
        rev[2*b^r2].push_back(2*a^r1);
    }

    // Add a 2-SAT clause.
    void addClause(int a, int b, bool r1, bool r2) {
        connect(a, b, !r1, r2);
        connect(b, a, !r2, r1);
    }

    // a ∨ b
    void addOr(int a, int b) {
        addClause(a, b, false, false);
    }

    // ⅂a ∨ ⅂b
    void addNand(int a, int b) {
        addClause(a, b, true, true);
    }

    // a => b. Equivalent to: ⅂a ∨ b
    void addImplication(int a, int b) {
        addClause(a, b, true, false);
    }

    // a <=> b. Equivalent to a => b and b => a
    void addEquivalence(int a, int b) {
        addImplication(a, b);
        addImplication(b, a);
    }

    // a ∨ b, but not a ∧ b
    void addExclusion(int a, int b) {
        addOr(a, b);
        addNand(a, b);
    }

    // Assume that a has value r.
    void addAssumption(int a, bool r) {
        addClause(a,a,r,r);
    }

    bool satisfiable() {
        return !satisfy().empty();
    }

};

int main()
{
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    string garbage1,garbage2;
    int n,m;
    cin >> garbage1 >> garbage2 >> n >> m;
    Sat2 S(n);
    for(int i=0;i<m;i++)
    {
        int a,b,trash;
        cin >> a >> b >> trash;
        bool r1 = a < 0,r2 = b < 0;
        a=abs(a)-1,b=abs(b)-1;
        S.addClause(a,b,r1,r2);
    }
    auto sol=S.satisfy();
    if(sol.empty())
        cout << "s UNSATISFIABLE\n";
    else
    {
        cout << "s SATISFIABLE\nv ";
        for(int i=0;i<n;i++)
        {
            int v = sol[i];
            cout << (2*v-1) * (i+1) << ' ';
        }
        cout << 0 << '\n';
    }
}

Problems :
https://judge.yosupo.jp/problem/two_sat

⚠️ **GitHub.com Fallback** ⚠️