POJ--3678[Katu Puzzle] 第三道2-SAT

45 篇文章 0 订阅
题目大意:

一些点,点的取值可以是0或者1,没有告诉你具体取值。

一些边,有权值,有运算方式(并,或,异或),要求和这条边相连的两个点经过边上的运算后的结果是边的权值。

问你有没有可能把每个点赋值满足所有边的要求。

 

思路分析:

每个点只有0,1两种值,并且和边对面的点有约束条件,所以可以转化为2-sat问题。

令i表示点i取1,i + n表示点i取0.

关键:
(1):and 等于 1时,要求i和j必须为1,不能为0.

不能为0的处理时:如果i取0,那么i就要取1.

即:i + n -> i。
(2):or 等于 0时,要求i和j必须为0,不能为1.

不能为1的处理时:如果i取1,那么i就要取0.

即:i -> i + n。

 

CODE:

/*POJ2-SAT第三题*/
/*关键处理:不能为0和不能为1的处理*/
/*AC代码:94ms*/
#include <iostream>
#define MAXN 4005
struct edge
{
	int v,next;
	edge(){}
	edge(int v1,int next1)
	{v=v1;next=next1;}
}E[4000005];
int head[MAXN],ecnt;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
bool Instack[MAXN];
int Index,cnt,top,N,M;
void Insert(int u,int v)
{
	E[ecnt]=edge(v,head[u]);
	head[u]=ecnt++; 
}
void Tarjan(int u)
{
	int v,i;
	Low[u]=DFN[u]=++Index;
	Instack[u]=true;
	Stack[++top]=u;
	for(i=head[u];i!=-1;i=E[i].next)
	{
		v=E[i].v;
		if(!DFN[v])
		{
			Tarjan(v);
			if(Low[u]>Low[v])
				Low[u]=Low[v];
		}
		else if(Instack[v]&&Low[u]>DFN[v])
			Low[u]=DFN[v];
	}
	if(Low[u]==DFN[u])
	{
		cnt++;
		do{
			v=Stack[top--];
			Instack[v]=false;
			Belong[v]=cnt;
		}while(u!=v);
	}
	return;
}
void Build_Map()
{
	int i,u,v,c;
	char s[5];
	for(i=0;i<M;i++)
	{
		scanf("%d%d%d%s",&u,&v,&c,s);
		if(s[0]=='A')
		{
			if(c==1)
			{
				Insert(u+N,u);//不能为0的处理
				Insert(v+N,v);
				//Insert(u,v);
				//Insert(v,u);
			}
			else
			{
				Insert(u,v+N);
				Insert(v,u+N);
			}
		}
		else if(s[0]=='O')
		{
			if(c==1)
			{
				Insert(u+N,v);
				Insert(v+N,u);
			}
			else
			{
				Insert(u,u+N);//不能为1的处理
				Insert(v,v+N);
				//Insert(u+N,v+N);
				//Insert(v+N,u+N);
			}
		}
		else
		{
			if(c==1)
			{
				Insert(u,v+N);
				Insert(v+N,u);
				Insert(v,u+N);
				Insert(u+N,v);
			}
			else
			{
				Insert(v,u);
				Insert(u,v);
				Insert(v+N,u+N);
				Insert(u+N,v+N);
			}
		}
	}
}
bool Sat()
{
	int i;
	memset(Instack,false,sizeof(Instack));
	memset(DFN,0,sizeof(DFN));
	memset(Low,0,sizeof(Low));
	Index=cnt=top=0;
	for(i=0;i<2*N;i++)
	{if(!DFN[i]) Tarjan(i);}
	for(i=0;i<N;i++)
		if(Belong[i]==Belong[i+N])
			return false;
		return true;
}
int main()
{
	while(scanf("%d%d",&N,&M)!=EOF)
	{
		ecnt=0;
		memset(head,-1,sizeof(head));
		Build_Map();
		if(Sat()) printf("YES\n");
		else printf("NO\n"); 
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__简言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值