2-SAT
给出若干个限制条件,形如 xi opt xj=num(opt={^,&,|},num={0,1}),给出一组可行解
//时间复杂度O(n+m)
//当 x 所在的强连通分量的拓扑序在 ¬x 所在的强连通分量的拓扑序之后取 x
//为真 ,注意我们得到的是拓扑逆序,所以要写成color[x] < color[¬x]
// 其中 i 表示 ¬x,用 i+n 表示 x
p ∨ q == ¬p → q ∧ ¬q → p
p || q == -p ->q && -q -> p
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2000007, M = 5000007, INF = 0x3f3f3f3f;
int n, m;
int dfn[N], low[N], num;
bool vis[N], ins[N];
int a[N], scc_cnt;
int scc_id[N], color[N];
int stk[N], top;
int ver[M], nex[M], head[N], tot;
void add(int x, int y){
ver[tot] = y;
nex[tot] = head[x];
head[x] = tot ++ ;
}
void tarjan(int x)
{
dfn[x] = low[x] = ++ num;
stk[++ top] = x;
ins[x] = true;
for(int i = head[x]; ~i; i = nex[i]){
int y = ver[i];
if(!dfn[y]){
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if(ins[y])
low[x] = min(low[x], dfn[y]);
}
if(low[x] == dfn[x]){
int y;
++ scc_cnt;
do{
y = stk[top -- ];
ins[y] = false;
scc_id[y] = scc_cnt;
color[y] = scc_cnt;
}while(x != y);
}
}
int main()
{
memset(head, -1, sizeof head);
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++ i){
int p, q ,c ,d;
scanf("%d%d%d%d", &p, &c, &q, &d);
if(c && d){// p 且 q -p-> q && -q -> p
add(p, q + n);
add(q, p + n);
}
else if(!c && d){//p -> q && -q -> -p
add(p + n, q + n);
add(q, p);
}
else if(c && !d){//-p -> -q && q -> p
add(p, q);
add(q + n, p + n);
}
else if(!c && !d){//p -> -q && q -> -p
add(p + n, q);
add(q + n, p);
}
}
for(int i = 1; i <= 2 * n; ++ i){
if(!dfn[i])
tarjan(i);
}
for(int i = 1 ;i <= n; ++ i) {
if(color[i] == color[i + n]){
puts("IMPOSSIBLE");
return 0;
}
}
puts("POSSIBLE");
for(int i = 1; i <= n; ++ i)
printf("%d ", (color[i] > color[i + n]));
puts("");
return 0;
}