Katu Puzzle(2-SAT)

Katu Puzzle(ACwing)

Description

有 N 个变量 X0 ~ XN-1,每个变量的可能取值为 0 或 1 。

给定 M 个算式,每个算式形如 Xa oXc,其中 a,b 是变量编号,c 是数字 0 或 1 ,op 是 and,or,xor 三个位运算之一。

求是否存在对每个变量的合法赋值,使所有算式都成立。

输入格式

第一行包含两个整数 N 和 M 。

接下来 M 行,每行包含三个整数a b c,以及一个位运算(and,or,xor中的一个)。

输出格式

输出结果,如果存在,输出“YES”,否则输出“NO”

数据范围

1N1000,
1M≤1e6

Solution

每个变量只有两个可能值,且不同变量间有约束,符合2-SAT的模型。

将位运算式子转化成约束条件,例如

a and b = 0 表示

若 Xa = 1 ,则必须 Xb = 0。从 a+N 到 b 连有向边,

若 Xb = 1 ,则必须 Xa = 0。从 b+N 到 a 连有向边。

其他同理,详见代码

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=2e3+10,M=2e6+10;
int head[N],nxt[M],to[M],cnt;
int n,m,a,b,c,d[N],scc;
int dfn[N],low[N],tot,st[N],top;
char s[10];
bool in[N];
void add(int x,int y)
{
    to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++cnt;
    st[++top]=u,in[u]=true;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(in[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        scc++;
        int z;
        do{
            z=st[top--];
            in[z]=false,d[z]=scc;
        }while(z!=u);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    while(m--)
    {
        scanf("%d%d%d%s",&a,&b,&c,s);
        if(s[0]=='A')
        {
            if(c==0) add(a+n,b),add(b+n,a);
            else add(a,a+n),add(b,b+n);
        }
        else if(s[0]=='O')
        {
            if(c==0) add(a+n,a),add(b+n,b);
            else add(a,b+n),add(b,a+n);
        }
        else if(s[0]=='X')
        {
            if(c==0) add(a,b),add(b,a),add(a+n,b+n),add(b+n,a+n);
            else add(a,b+n),add(b,a+n),add(a+n,b),add(b+n,a);
        }
    }
    for(int i=1;i<=2*n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
        if(d[i]==d[i+n])
        {
            puts("NO");
            return 0;
        }
    puts("YES");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12348492.html
今日推荐