Cod sursa(job #2725042)

Utilizator Alex_tz307Lorintz Alexandru Alex_tz307 Data 18 martie 2021 12:32:15
Problema 2SAT Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4 kb
#include <bits/stdc++.h>
#define ABS(x) ((x) >= 0 ? (x) : -(x))

using namespace std;

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

/// Idee:
/// v - sau(|)
/// ^ - si(&)
/// ~ - not/negatie(!)
/// consideram expresia: (p1 v p3) ^ (~p1 v p2) ^ (~p2 v p3)
/// pentru a o satisface(adica sa aiba valoarea true), toate parantezele trebuie evaluate la true
/// consider de exemplu p1
/// am 2 variante pentru p1: este true sau ~p1 este true(adica p1 este false)
/// daca ma aflu in situatia a 2-a(~p1 este true), asta implica in prima paranteza p3 true
/// analog, daca as avea ~p3 true, atunci asta ar implica p1 true
/// pe baza acestor informatii extrase din toate parantezele construim un graf al implicatiilor
/// impart graful obtinut in componente tare conexe
/// o componenta tare conexa a unui graf contine un ciclu care are pe el toate nodurile componentei
/// astfel vom stabili ca valoarea fiecarei variabile dintr-o componenta este true(puteam lucra si cu false)

const int NMAX = 2e5 + 5; /// numarul maxim de variabile(trebuie dublata valoarea maxima pentru ca apar si negatiile)
int N, M; /// numarul de variabile, numarul de expresii
vector<int> G[NMAX], GT[NMAX]; /// graful implicatiilor, respectiv transpunerea lui(folosesc la CTC)
short viz[NMAX];
stack<int> S;
int ctc_cnt, ctc_index[NMAX]; /// numarul de componente tare conexe, din ce componenta face parte fiecare nod
vector<int> ctc[NMAX]; /// nodurile din fiecare componenta tare conexa
int deg[NMAX]; /// gradul interior al fiecarui nod din graful componentelor tare conexe
short sol[NMAX]; /// solutia gasita

int nod(int v) { /// valorile normale sunt de la 1 la N, iar cele negate de la N + 1 la 2 * N
  if (v < 0)
    return ABS(v) + N;
  return v;
}

int neg(int v) {
  if (v > N)
    return v - N;
  return v + N;
}

void read_input() {
  fin >> N >> M;
  for (int i = 0; i < M; ++i) {
    int v1, v2;
    fin >> v1 >> v2;
    v1 = nod(v1), v2 = nod(v2);
    int neg_v1 = neg(v1), neg_v2 = neg(v2);
    G[neg_v1].emplace_back(v2);
    GT[v2].emplace_back(neg_v1);
    G[neg_v2].emplace_back(v1);
    GT[v1].emplace_back(neg_v2);
  }
  fin.close();
}

void dfs1(int u) {
  viz[u] = 1;
  for(int v : G[u])
    if (!viz[v])
      dfs1(v);
  S.emplace(u);
}

void dfs2(int u) {
  viz[u] = 2;
  ctc_index[u] = ctc_cnt;
  ctc[ctc_cnt].emplace_back(u);
  for (int v : GT[u])
    if (viz[v] == 1)
      dfs2(v);
}

void find_CTC() {
  for (int u = 1; u <= 2 * N; ++u)
    if (!viz[u])
      dfs1(u);
  while (!S.empty()) {
    int u = S.top();
    S.pop();
    if (viz[u] == 1) {
      ++ctc_cnt;
      dfs2(u);
    }
  }
}

void solve() {
  for (int u = 1; u <= N; ++u)
    if (ctc_index[u] == ctc_index[u + N]) { /// daca p1 si ~p1 sunt in acceasi componenta tare conexa trebuie sa fie ambele true, contradictie, deci nu avem solutie
      fout << "-1\n";
      return;
    }
  for (int u = 1; u <= 2 * N; ++u)
    for (int v : G[u])
      if (ctc_index[u] != ctc_index[v])
        ++deg[ctc_index[v]];
  queue<int> Q; /// consider graful ctc-urilor in ordinea inversa topologica a lui(e un DAG)
  for (int u = 1; u <= ctc_cnt; ++u)
    if (deg[u] == 0)
      Q.emplace(u);
  assert(!Q.empty());
  for (int u = 1; u <= N; ++u)
    sol[u] = -1;
  while (!Q.empty()) {
    int curr_ctc = Q.front();
    Q.pop();
    assert(curr_ctc <= ctc_cnt);
    for (int u : ctc[curr_ctc]) {
      int real_v = u;
      bool to_assign = false;
      if (real_v > N) {
        real_v -= N;
        to_assign = true;
      }
      if (sol[real_v] == -1)
        sol[real_v] = to_assign;
      assert(ctc_index[u] == curr_ctc);
      for (int v : G[u]) {
        int adj_ctc = ctc_index[v];
        if (curr_ctc == adj_ctc)
          continue;
        if (--deg[adj_ctc] == 0)
          Q.emplace(adj_ctc);
      }
    }
  }
  for (int u = 1; u <= N; ++u)
    fout << sol[u] << ' ';
  fout << '\n';
}

int main() {
  read_input();
  find_CTC();
  solve();
  fout.close();
  return 0;
}