【2-SAT】【tarjan】【建图】POJ 3678 Katu Puzzle

【题目】http://poj.org/problem?id=3678

【题意】总共有n个数,m个式子,式子是Xa op Xb = c,问有没有这样n个数使这m个式子全部满足

【思路】将每个Xn分成0和1,1-n是当Xn取0时的点,n+1到n+n是当X取1时的点。当一个运算要求当Xa是xx时,Xb一定是xx时,从Xa到Xb连一条边。另外,当AND为1时,要求Xa和Xb必须是1,那么从Xa=0连边到Xa=1,Xb=0连边到Xb=1,以保证选到Xa=0的时候一定会无解。

在基本的2-SAT基础上,增加了诸如“a必须为1”的条件。若a必须为1,则连边a0 --> a1,这样只要一选a0,自然就矛盾了。 

【参考】http://blog.sina.com.cn/s/blog_68629c7701010gf1.html 

【代码】

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int M=200005;

int n,m;
int linkx[M],linky[M];

int head[M];
class node
{
public:
    int v,next;
};
node edge[M];
int ei;
int Stack[M],si;
int DFN[M],LOW[M],tot;
int inthestack[M];
int scc;
int belong[M];

void tarjan(int x)
{
    Stack[++si]=x;
    inthestack[x]=1;
    DFN[x]=LOW[x]=++tot;
    for(int i=head[x]; i!=-1; i=edge[i].next)
    {
        int& t=edge[i].v;
        if(!DFN[t])
        {
            tarjan(t);
            LOW[x]=min(LOW[x],LOW[t]);
        }
        else if(DFN[t]&&inthestack[t])
        {
            LOW[x]=min(LOW[x],DFN[t]);
        }
    }
    if(DFN[x]==LOW[x])
    {
        scc++;
        do
        {
            belong[Stack[si]]=scc;
            inthestack[Stack[si]]=0;
            si--;
        }
        while(x!=Stack[si+1]);
    }
    return;
}

void addedge(int u,int v)
{
    edge[++ei].v=v;
    edge[ei].next=head[u];
    head[u]=ei;
    return;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(inthestack,0,sizeof(inthestack));
    memset(LOW,0,sizeof(LOW));
    memset(DFN,0,sizeof(DFN));
    scc=tot=ei=si=0;
    return;
}

//void makeedge()
//{
//    for(int i=1; i<=m; i++)
//    {
//        for(int j=i+1; j<=m; j++)
//        {
//            if((linkx[i]<linkx[j]&&linky[i]>linkx[j]&&
//                    linky[i]<linky[j])||
//                    (linkx[j]<linkx[i]&&linky[j]>linkx[i]&&
//                     linky[j]<linky[i])
//              )
//            {
//                addedge(i,j+m);
//                addedge(j+m,i);
//                addedge(i+m,j);
//                addedge(j,i+m);
//            }
//        }
//    }
//}



int main()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        a++,b++;
        string s;
        cin>>s;
        if(s=="OR")
        {
            if(c==0)
            {
                addedge(a+n,a);//这里如果a or b=0时很明显a和b都不可能等于1。
                addedge(b+n,b);//所以连接 a1->a,b1->b,以保证a或b取1时一定无解
                addedge(a,b);
                addedge(b,a);
            }
            else if(c==1)
            {
                addedge(a,b+n);
                addedge(b,a+n);
            }
        }
        else if(s=="XOR")
        {
            if(c==0)
            {
                addedge(a,b);
                addedge(b,a);
                addedge(a+n,b+n);
                addedge(b+n,a+n);
            }
            else if(c==1)
            {
                addedge(a,b+n);
                addedge(b+n,a);
                addedge(a+n,b);
                addedge(b,a+n);
            }
        }
        else if(s=="AND")
        {
            if(c==0)
            {
                addedge(a+n,b);
                addedge(b+n,a);
            }
            else if(c==1)
            {
                addedge(a,a+n);//这里如果a and b=1时很明显a和b都不可能等于0。
                addedge(b,b+n);//所以连接 a->a1,b->b1,以保证a或b为0时一定无解
                addedge(a+n,b+n);
                addedge(b+n,a+n);
            }
        }
    }
    for(int i=1; i<=2*n; ++i) //缩点
        if(!DFN[i])
            tarjan(i);
    for(int i=1; i<=n; i++)
    {
        //printf("%d: %d  %d\n",i-1,belong[i],belong[i+n]);
        if(belong[i]==belong[i+n])
        {
            cout<<"NO"<<endl;
            return 0;
        }
    }
    cout<<"YES"<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_32259423/article/details/81416477
今日推荐