洛谷P4782 2-SAT【模板】

2-SAT是一类非常有趣的问题,他会给你一堆形如   i   true/false     j   true/false的条件,表示选a必须选b或者必须不选b,反之亦然

求解方法是用到的拆点+tarjan,我们把一个点拆为选  i   和不选   i+n,然后分别于j的反状态连边,若存在满足条件的状态,那么他在图中表示出来肯定是一条链,否则i和i+n就会同时出现

代码

//By AcerMo
#include
#include
#include
#include
#include
#include
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;
stacks;
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;
}

 

你可能感兴趣的:(图论-Tarjan)