Pagini recente » Cod sursa (job #2303201) | Cod sursa (job #314447) | Cod sursa (job #2027023) | Cod sursa (job #198674) | Cod sursa (job #2725042)
#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;
}