Cod sursa(job #2289728)

Utilizator preda.andreiPreda Andrei preda.andrei Data 25 noiembrie 2018 09:52:46
Problema 2SAT Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.68 kb
#include <fstream>
#include <queue>
#include <stack>
#include <vector>

using namespace std;

struct Node
{
    vector<int> edges;
    int time = -1;
    int low = -1;

    int comp = -1;
    bool on_stack = false;
};

class TwoSat;

class Graph
{
public:
    friend class TwoSat;

    Graph(int vars)
        : nodes_(vector<Node>(2 * vars + 1)),
          vars_(vars) {}

    void AddClause(int a, int b);

private:
    vector<Node> nodes_;
    int vars_;

    int GetRealNode(int node) const;
    int GetMathNode(int node) const;
};

int Graph::GetRealNode(int node) const
{
    if (node > 0) {
        return node;
    }
    return vars_ - node;
}

int Graph::GetMathNode(int node) const
{
    if (node <= vars_) {
        return node;
    }
    return vars_ - node;
}

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

    auto real_not_a = GetRealNode(-a);
    auto real_not_b = GetRealNode(-b);

    nodes_[real_not_a].edges.push_back(real_b);
    nodes_[real_not_b].edges.push_back(real_a);
}

class TwoSat
{
public:
    static vector<bool> FindSolution(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 last_node, vector<int> &order);
};

vector<bool> TwoSat::FindSolution(Graph &g)
{
    vector<bool> sol(g.vars_, false);
    vector<bool> is_set(g.vars_, false);

    auto order = FindComps(g);
    for (int i = 1; i <= g.vars_; i += 1) {
        auto not_i = g.GetRealNode(-i);
        if (g.nodes_[i].comp == g.nodes_[not_i].comp) {
            return vector<bool>();
        }
    }

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

        if (!is_set[abs(node) - 1]) {
            sol[abs(node) - 1] = (node < 0);
            is_set[abs(node) - 1] = true;
        }
    }

    return sol;
}

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

void TwoSat::Dfs(Graph &g, int node, stack<int> &st, vector<int> &order)
{
    auto &curr_node = g.nodes_[node];

    static auto time = 0;
    curr_node.time = curr_node.low = (time += 1);

    st.push(node);
    curr_node.on_stack = true;

    for (const auto &next : curr_node.edges) {
        auto &next_node = g.nodes_[next];
        if (next_node.time == -1) {
            Dfs(g, next, st, order);
        }
        if (next_node.on_stack) {
            curr_node.low = min(curr_node.low, next_node.low);
        }
    }

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

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

    while (st.top() != last_node) {
        g.nodes_[st.top()].comp = next_comp;
        order.push_back(st.top());
        st.pop();
    }

    g.nodes_[st.top()].comp = next_comp;
    order.push_back(st.top());
    st.pop();
}

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::FindSolution(graph);
    if (res.empty()) {
        fout << "-1\n";
    } else {
        for (const auto &val : res) {
            fout << (val ? 1 : 0) << " ";
        }
        fout << "\n";
    }

    return 0;
}