版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/81947338
2-SAT是一类非常有趣的问题,他会给你一堆形如 i true/false j true/false的条件,表示选a必须选b或者必须不选b,反之亦然
求解方法是用到的拆点+tarjan,我们把一个点拆为选 i 和不选 i+n,然后分别于j的反状态连边,若存在满足条件的状态,那么他在图中表示出来肯定是一条链,否则i和i+n就会同时出现
代码
//By AcerMo
#include<cmath>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=2e6+50;
int n,m;
int head[M],nxt[M],to[M],cnt;
int dfn[M],low[M],fa[M],vis[M],ind,ti;
stack<int>s;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y)
{
to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;
return ;
}
inline void tarjan(int x)
{
dfn[x]=low[x]=++ind;vis[x]=1;s.push(x);
for (int i=head[x];i;i=nxt[i])
{
if (!dfn[to[i]])
tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if (vis[to[i]])
low[x]=min(low[x],dfn[to[i]]);
}
if (low[x]==dfn[x])
{
ti++;int u=-1;
while (u!=x)
{
u=s.top();s.pop();
fa[u]=ti;vis[u]=0;
}
}
return ;
}
inline int t_sat()
{
for (int i=1;i<=2*n;i++)
if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;i++)
if (fa[i]==fa[i+n]) return 0;
return 1;
}
signed main()
{
n=read();m=read();
for (int i=1;i<=m;i++)
{
int a=read(),fla=read();
int b=read(),flb=read();
int na=fla^1,nb=flb^1;
add(a+na*n,b+flb*n);
add(b+nb*n,a+fla*n);
}
if (!t_sat()) puts("IMPOSSIBLE");
else
{
puts("POSSIBLE");
for (int i=1;i<=n;i++)
cout<<(fa[i]>fa[i+n])<<" ";
}
return 0;
}