Cod sursa(job #2352026)

Utilizator preda.andreiPreda Andrei preda.andrei Data 22 februarie 2019 21:43:02
Problema 2SAT Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.57 kb
#include <fstream>
#include <stack>
#include <vector>

using namespace std;

class Graph
{
public:
    Graph(int size) : nodes_(vector<Node>(2 * size)) {}

    int Vars() const { return nodes_.size() / 2; }

    void AddClause(int a, int b);

    friend class TwoSat;

private:
    int GetRealNode(int math) const;
    int GetMathNode(int real) const;

    struct Node
    {
        vector<int> edges;
        int comp = 0;
        int time = 0;
        int low = 0;
        bool in_stack = false;
    };

    vector<Node> nodes_;
};

int Graph::GetRealNode(int math) const
{
    if (math > 0) {
        return math - 1;
    }
    return Vars() - math - 1;
}

int Graph::GetMathNode(int real) const
{
    if (real < Vars()) {
        return real + 1;
    }
    return -(real - Vars() + 1);
}

void Graph::AddClause(int a, int b)
{
    auto real_a = GetRealNode(a);
    auto real_b = GetRealNode(b);

    auto not_a = GetRealNode(-a);
    auto not_b = GetRealNode(-b);

    nodes_[not_a].edges.push_back(real_b);
    nodes_[not_b].edges.push_back(real_a);
}


class TwoSat
{
public:
    static vector<bool> Solve(Graph &g);

private:
    static vector<int> FindComps(Graph &g);
    static void Dfs(Graph &g, int node, stack<int> &st, vector<int> &order);
    static void ExtractComp(Graph &g, stack<int> &st, int node, vector<int> &order);
};

void TwoSat::ExtractComp(Graph &g, stack<int> &st, int node, vector<int> &order)
{
    static auto next_comp = 0;
    next_comp += 1;

    while (order.empty() || order.back() != node) {
        order.push_back(st.top());
        g.nodes_[st.top()].comp = next_comp;
        g.nodes_[st.top()].in_stack = false;
        st.pop();
    }
}

void TwoSat::Dfs(Graph &g, int node, stack<int> &st, vector<int> &order)
{
    static auto time = 0;
    g.nodes_[node].low = g.nodes_[node].time = (time += 1);

    st.push(node);
    g.nodes_[node].in_stack = true;

    for (const auto &next : g.nodes_[node].edges) {
        if (g.nodes_[next].time == 0) {
            Dfs(g, next, st, order);
        }
        if (g.nodes_[next].in_stack) {
            g.nodes_[node].low = min(g.nodes_[node].low, g.nodes_[next].low);
        }
    }

    if (g.nodes_[node].low >= g.nodes_[node].time) {
        ExtractComp(g, st, node, order);
    }
}

vector<int> TwoSat::FindComps(Graph &g)
{
    vector<int> order;
    for (size_t i = 0; i < g.nodes_.size(); i += 1) {
        if (g.nodes_[i].time == 0) {
            stack<int> st;
            Dfs(g, i, st, order);
        }
    }
    return order;
}

vector<bool> TwoSat::Solve(Graph &g)
{
    auto order = FindComps(g);
    vector<bool> res(g.Vars(), false);
    vector<bool> used(g.Vars(), false);

    for (int i = order.size() - 1; i >= 0; i -= 1) {
        auto real_node = order[i];
        auto math_node = g.GetMathNode(real_node);
        auto not_node = g.GetRealNode(-math_node);

        if (g.nodes_[real_node].comp == g.nodes_[not_node].comp) {
            return vector<bool>();
        }

        auto node = abs(math_node) - 1;
        if (!used[node]) {
            res[node] = (math_node > 0 ? false : true);
            used[node] = true;
        }
    }
    return res;
}


int main()
{
    ifstream fin("2sat.in");
    ofstream fout("2sat.out");

    int vars, clauses;
    fin >> vars >> clauses;

    Graph graph(vars);
    for (auto i = 0; i < clauses; i += 1) {
        int a, b;
        fin >> a >> b;
        graph.AddClause(a, b);
    }

    auto res = TwoSat::Solve(graph);
    if (res.empty()) {
        fout << "-1\n";
        return 0;
    }

    for (const auto &val : res) {
        fout << val << " ";
    }
    fout << "\n";

    return 0;
}