有
n
n
n 个布尔变量
x
1
x_1
x1
∼
\sim
∼
x
n
x_n
xn,另有
m
m
m 个需要满足的条件,每个条件的形式都是 「
x
i
x_i
xi 为 true
/ false
或
x
j
x_j
xj 为 true
/ false
」。比如 「
x
1
x_1
x1 为真或
x
3
x_3
x3 为假」、「
x
7
x_7
x7 为假或
x
2
x_2
x2 为假」。
2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
第一行两个整数 n n n 和 m m m,意义如题面所述。
接下来 m m m 行每行 4 4 4 个整数 i i i, a a a, j j j, b b b,表示 「 x i x_i xi 为 a a a 或 x j x_j xj 为 b b b」( a , b ∈ { 0 , 1 } a, b\in \{0,1\} a,b∈{0,1})
如无解,输出 IMPOSSIBLE
;否则输出 POSSIBLE
。
下一行 n n n 个整数 x 1 ∼ x n x_1\sim x_n x1∼xn( x i ∈ { 0 , 1 } x_i\in\{0,1\} xi∈{0,1}),表示构造出的解。
3 1
1 1 3 0
POSSIBLE
0 0 0
1 ≤ n , m ≤ 1 0 6 1\leq n, m\leq 10^6 1≤n,m≤106 , 前 3 3 3 个点卡小错误,后面 5 5 5 个点卡效率。
由于数据随机生成,可能会含有( 10 0 10 0)之类的坑,但按照最常规写法的写的标程没有出错,各个数据点卡什么的提示在标程里。
对于一个
a
o
r
b
a\ or\ b
a or b的表达式,我们可以拆成
(
!
a
a
n
d
b
)
o
r
(
!
b
a
n
d
a
)
o
r
(
a
a
n
d
b
)
(!a\ and\ b)\ or\ (!b\ and\ a)\ or\ (a\ and\ b)
(!a and b) or (!b and a) or (a and b)
我们可以建图
!
a
→
b
!a→ b
!a→b和
!
b
→
a
!b→a
!b→a表示选了
!
a
!a
!a就得选
b
b
b,反之亦然。
习惯上,我们给缩点后的图排一个拓扑序,当 x x x 所在强连通分量的拓扑序在 ! x !x !x 所在的强连通分量的拓扑序之后的话我们就给 x x x 取真。
这题tarjan缩完点就已经有个顺序了,不过这是反着的拓扑序,所以比较关系是反着的。
#include
#define int long long
using namespace std;
const int N=2e6+77;
int dfn[N],low[N],b[N],s[N],c[N],ls[N],cnt,id,top,tot;
struct E
{
int to,next;
}e[N<<1];
void add(int u,int v)
{
e[++cnt].to=v; e[cnt].next=ls[u]; ls[u]=cnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++tot; b[u]=1;
s[++top]=u;
for(int i=ls[u]; i; i=e[i].next)
{
int v=e[i].to;
if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
else if(b[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
id++;
while(s[top+1]!=u)
{
c[s[top]]=id;
b[s[top]]=0; top--;
}
}
}
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=m; i++)
{
int x,y,a,b;
cin>>x>>a>>y>>b;
x<<=1; y<<=1;
x^=a; y^=b;
add(x^1,y); add(y^1,x);
}
for(int i=2; i<=2*n+1; i++) if(!dfn[i]) tarjan(i);
for(int i=1; i<=n; i++)
{
if(c[i*2]==c[(i*2)^1])
{
cout<<"IMPOSSIBLE"; return;
}
}
cout<<"POSSIBLE\n";
for(int i=1; i<=n; i++)
{
if(c[i<<1]<c[(i<<1)^1]) cout<<"0 ";else cout<<"1 ";
}
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0),cout.tie(0);
int T=1;
// cin>>T;
while(T--)
{
solve();
}
}