POJ 3678 Katu Puzzle(2-SAT)

版权声明:抱最大的希望,为最大的努力,做最坏的打算。 https://blog.csdn.net/qq_37748451/article/details/88089040

题目来源:
http://poj.org/problem?id=3678

题意:
一个N个顶点和M条边的有向图,每个顶点能取0或1两个值.现在每条边被一个操作符(or,and,xor)以及一个值(0或1)标记了,表示a与b按操作符运算的结果是值(0或1).问你该有向图是否有可行解?

分析:

由于每个点只能取0或1两个值,所以我们把该问题转化为2-SAT问题.原图中的每个点对应2-SAT中的每个点.对于每种运算有下列转换方式:

a and b = 0 转换为 a=0 或 b=0

a and b = 1 转换为 a=1 且 b=1 (只要a为0或b为0必然引起矛盾)

a or b = 0 转换为 a+n->a  b+n->b(只要a为1或b为1必然引起矛盾)

a or b = 1 转换为 a=1 或b=1

a xorb=0 转换为 a=1且b=1 或 a=0且b=0 即连下面的边:

a->b    b->a    a+n->b+n   b+n->a+n.

a xor b=1 转换为a=1且b=0 或a=0且b=1 则连下面的边:

a+n->b      b->a+n    a->b+n    b+n->a

代码:

#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
const int maxn=41000;
int op[maxn],vis[maxn],low[maxn],dfn[maxn];
int pt[maxn],stk[maxn],color[maxn],pos[maxn],deg[maxn];
vector<int>vc[maxn],vc2[maxn];
int n,m,sig,cnt,tot,cont;
void add(int x,int y){
    vc[x].push_back(y);
}
void top(){
    memset(pt,0,sizeof(pt));
    queue<int>s;
    for(int i=1;i<=sig;i++){
        if(deg[i]==0) s.push(i);
    }
    while(!s.empty()){
        int u=s.front();
        if(pt[u]==0){
            pt[u]=1;
            pt[pos[u]]=2;
        }
        s.pop();
        for(int i=0;i<vc2[u].size();i++){
            int v=vc2[u][i];
            deg[v]--;
            if(deg[v]==0) s.push(v);
        }
    }
    cont=0;
    for(int i=1;i<=n;i++) {
        if(pt[color[i]]==1) op[cont++]=i;
    }
}
void tarjan(int u){
    vis[u]=1;
    dfn[u]=low[u]=cnt++;
    stk[++tot]=u;
    for(int i=0;i<vc[u].size();i++){
        int v=vc[u][i];
        if(vis[v]==0) tarjan(v);
        if(vis[v]==1) low[u]=min(low[u],low[v]);
    }
    if(low[u]==dfn[u]) {
        sig++;
        do{
            vis[stk[tot]]=-1;
            color[stk[tot]]=sig;
        }while(stk[tot--]!=u);
    }
}
void init(){
    sig=0;cnt=1;tot=-1;
    memset(deg,0,sizeof(deg));
    memset(stk,0,sizeof(stk));
    memset(dfn,0,sizeof(dfn));
    memset(vis,0,sizeof(vis));
    memset(color,0,sizeof(color));
    for(int i=0;i<maxn;i++) {
        vc[i].clear();
        vc2[i].clear();
    }
}
int solve(){
    for(int i=1;i<=n*2;i++) {
        if(vis[i]==0) tarjan(i);
    }
    for(int i=1;i<=n;i++) {
        if(color[i]==color[i+n]) return 0;
        pos[color[i]]=color[i+n];
        pos[color[i+n]]=color[i];
    }
    for(int i=1;i<=n*2;i++){
        for(int j=0;j<vc[i].size();j++){
            int v=vc[i][j];
            if(color[i]!=color[v]){
                deg[color[i]]++;
                vc2[color[v]].push_back(color[i]);
            }
        }
    }
    top();
    return 1;
}
int main()
{
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<m;i++){
            int x,y,z;
            char op[10];
            scanf("%d%d%d%s",&x,&y,&z,op);
            x++;
            y++;
            /*int xx=x,yy=y;
            if(x<0) x=-x;
            if(y<0) y=-y;
            if(xx>0&&yy>0) {add(x+n,y);add(y+n,x);}
            if(xx>0&&yy<0) {add(x+n,y+n);add(y,x);}
            if(xx<0&&yy>0) {add(x,y);add(y+n,x+n);}
            if(xx<0&&yy<0) {add(x,y+n);add(y,x+n);}*/
        if(op[0]=='A')
        {
            if(z==0)
            {
                add(x+n,y);
                add(y+n,x);
            }
            else if(z==1)
            {
                add(x,x+n);
                add(y,y+n);
            }
        }
        else if(op[0]=='O')
        {
            if(z==0)
            {
                add(x+n,x);
                add(y+n,y);
            }
            else if(z==1)
            {
                add(x,y+n);
                add(y,x+n);
            }
        }
        else if(op[0]=='X')
        {
            if(z==0)
            {
                add(x,y);
                add(x+n,y+n);
                add(y,x);
                add(y+n,x+n);
                /*TS.add_clause(a,0,b,0);
                TS.add_clause(a,1,b,1);
                TS.add_clause(b,0,a,0);
                TS.add_clause(b,1,a,1);*/
            }
            else if(z==1)
            {
                /*TS.add_clause(a,0,b,1);
                TS.add_clause(a,1,b,0);
                TS.add_clause(b,0,a,1);
                TS.add_clause(b,1,a,0);*/
                add(x,y+n);
                add(x+n,y);
                add(y,x+n);
                add(y+n,x);
            }
        }
       }
      if(solve()) printf("YES\n");
      else printf("NO\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37748451/article/details/88089040
今日推荐