题目大意:
一些点,点的取值可以是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;
}