2-SAT 学习笔记
对于一个命题:如果a,那么b
其逆命题为:如果b,那么a
其否命题为:如果¬a,那么¬b
其逆否命题为:如果¬b,那么¬a
∧表示与,∨表示或,¬表示非
原命题与逆否命题等值。逆命题与否命题等值
原命题与逆命题以及逆否命题与否命题之间没有关系
那么只需要 \(a -> b\) \(!b -> !a\) 就可以了
考虑 \(x_i\) 只有两个状态
此题说的是两者满足其一
那么可以转化成 满足前者且不满足后者 的关系
所以就这样了。
#include<bits/stdc++.h>
using namespace std ;
int n , m ;
const int N = 1e6 + 10 ;
struct node { int v , nxt ; } e[N << 1] ;
int head[N << 1] , cnt = 0 ;
inline void add(int u , int v) {
e[++ cnt] = { v , head[u] } ;
head[u] = cnt ;
}
int dfn[N << 1] , low[N << 1] , idx = 0 ;
int st[N << 1] , tp = 0 ;
int co[N << 1] , num = 0 ;
inline void tarjan(int u) {
dfn[u] = low[u] = ++ idx;
st[++ tp] = u;
for(register int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(! dfn[v]) {
tarjan(v) ;
low[u] = min(low[u] , low[v]) ;
}
else if(! co[v]){
low[u] = min(low[u] , dfn[v]) ;
}
}
if(low[u] == dfn[u]) {
co[u] = ++ num ;
while(st[tp] ^ u) {
co[st[tp --]] = num ;
} tp -- ;
}
}
signed main() {
#ifdef _WIN64
freopen("0.in" , "r" , stdin) ;
#endif
ios :: sync_with_stdio(false) ;
cin.tie(nullptr) ;
cout.tie(nullptr) ;
cin >> n >> m ;
for(register int i = 1 ; i <= m ; i ++) {
int a , f , b , f2 ;
cin >> a >> f >> b >> f2 ;
add(a + n * (f ^ 1) , b + n * (f2 & 1)) ;
add(b + n * (f2 ^ 1) , a + n * (f & 1)) ;
}
for(register int i = 1 ; i <= (n << 1) ; i ++)
if(! dfn[i]) tarjan(i) ;
for(register int i = 1 ; i <= n ; i ++)
if(co[i] == co[n + i]) { puts("IMPOSSIBLE") ; return 0 ; }
cout << "POSSIBLE\n" ;
for(register int i = 1 ; i <= n ; i ++) {
if(co[i] > co[i + n]) cout << 1 << ' ' ;
else cout << 0 << ' ' ;
}
return 0 ;
}