POJ 3678 Katu Puzzle 2-SAT

来源:互联网 发布:2017招聘软件排行 编辑:程序博客网 时间:2024/06/01 10:20

题意:

n个权值为0或1的数。
给定c个限制条件,形如:
XA xor XB=1(0)
XA or XB=1(0)
XA and XB=1(0)
判定是否可以安排这n个数的值,满足所有限制条件。


解析:

据说是2-SAT问题,反正我刚看到的时候满脑子都是建出来一个图之后判环。。
然而是有科学的做法的。
首先我们把每个点拆分成两个,分别代表改点取0或1.
科学的做法就是按照矛盾关系建边。
打一个比方
如果XA xor XB=1的话,
XA取1的时候,XB一定取0,所以连一条边。
XA取0的时候,XB一定取1,所以连一条边。
XB取1的时候,XA一定取0,所以连一条边。
XB取0的时候,XA一定取1,所以连一条边。
每一种限制条件都像这样讨论就好了。
但是需要注意的是,有的时候XA取0(1)一定无解。
所以我们要相应的从该点连向XA取1(0)的边,代表如果XA取0(1)一定无解。
最后我们只需要tarjan缩下点观察每个点取0或者1的两个点是否在一个强连通分量里即可。
如果有一个在的话,那么显然无解。
否则有解。


如果这道题要输出方案的话,显然有解的情况最后的图是一个DAG,拓扑染色一下即可。


代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 2100using namespace std;int head[N];int cnt,n,m;struct node{    int from,to,next;}edge[N*N];void init(){    memset(head,-1,sizeof(head));    cnt=1;}void edgeadd(int from,int to){    edge[cnt].from=from,edge[cnt].to=to;    edge[cnt].next=head[from];    head[from]=cnt++;}char s[5];int cnt_block,tot,top;int deep[N],low[N],sta[N],belong[N],ins[N];void tarjan(int now){    deep[now]=low[now]=++tot;    sta[++top]=now,ins[now]=1;    for(int i=head[now];i!=-1;i=edge[i].next)    {        int to=edge[i].to;        if(!deep[to])        {            tarjan(to);            low[now]=min(low[now],low[to]);        }else if(ins[to])low[now]=min(low[now],deep[to]);    }    if(deep[now]==low[now])    {        cnt_block++;        int t=-1;        do        {            t=sta[top--];            belong[t]=cnt_block;            ins[t]=0;        }while(t!=now);    }}int main(){    init();    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    {        int x,y,val;        scanf("%d%d%d%s",&x,&y,&val,s);        x++,y++;        if(s[0]=='X')        {            if(val==1)                edgeadd(x+n,y),edgeadd(y,x+n),edgeadd(x,y+n),edgeadd(y+n,x);            else                 edgeadd(x+n,y+n),edgeadd(y+n,x+n),edgeadd(x,y),edgeadd(y,x);        }else if(s[0]=='A')        {            if(val==1)                edgeadd(x,y),edgeadd(y,x),edgeadd(x+n,x),edgeadd(y+n,y);            else edgeadd(x,y+n),edgeadd(y,x+n);        }else        {            if(val==1)                edgeadd(x+n,y),edgeadd(y+n,x);            else edgeadd(x,x+n),edgeadd(y,y+n),edgeadd(x+n,y+n),edgeadd(y+n,x+n);        }    }    for(int i=1;i<=2*n;i++)        if(!deep[i])tarjan(i);    int flag=1;    for(int i=1;i<=n;i++)        if(belong[i]==belong[i+n]){flag=0;break;}    if(flag)puts("YES");    else puts("NO");}
0 0