ACWING 370. 卡图难题(2-SAT模板题)

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

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

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

输入格式
第一行包含两个整数N和M。

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

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

数据范围
1≤N≤1000,
1≤M≤106
输入样例:
4 4
0 1 1 AND
1 2 1 OR
3 2 0 AND
3 0 0 XOR
输出样例:
YES

思路:
今天CCPC热身出了个2-SAT模板题,赶紧学一学。

将x拆成x与x+n,建边然后跑tarjan判断x与x+n是否在同一连通分量,在就代表x取0的时候得取1,取1的时候得取0,这明显矛盾,此时无解,其他情况可以构造出解。

x+n->y,代表着x取1,那么y必须取0,
x->y+n,代表着x取0,那么y必须取1。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include <cstring>

using namespace std;

typedef long long ll;

const int maxn = 2e5 + 7;

vector<int>G[maxn];
int dfn[maxn],low[maxn],stk[maxn],ins[maxn],top,cnt,num;
int scc[maxn];

void tarjan(int x) {
    
    
    stk[++top] = x;
    low[x] = dfn[x] = ++num;
    ins[x] = 1;
    for(int i = 0;i < G[x].size();i++) {
    
    
        int v = G[x][i];
        if(!dfn[v]) {
    
    
            tarjan(v);
            low[x] = min(low[x],low[v]);
        } else if(ins[v]) {
    
    
            low[x] = min(low[x],dfn[v]);
        }
    }
    if(dfn[x] == low[x]) {
    
    
        ++cnt;
        int y;
        do {
    
    
            y = stk[top--];
            scc[y] = cnt;
            ins[y] = 0;
        } while(x != y);
    }
}

void add(int x,int y) {
    
    
    G[x].push_back(y);
}

int main() {
    
    
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i++) {
    
    
        int x,y,z;
        char op[10];
        scanf("%d%d%d%s",&x,&y,&z,op);
        if(op[0] == 'A') {
    
    
            if(z) {
    
    
                add(x,x + n);
                add(y,y + n);
            } else {
    
    
                add(x + n,y);
                add(y + n,x);
            }
        } else if(op[0] == 'O') {
    
    
            if(z) {
    
    
                add(x,y + n);
                add(y,x + n);
            } else {
    
    
                add(x + n,x);
                add(y + n,y);
            }
        } else if(op[0] == 'X') {
    
    
            if(z) {
    
    
                add(x,y + n);
                add(y,x + n);
                add(x + n,y);
                add(y + n,x);
            } else {
    
    
                add(x,y);
                add(y,x);
                add(x + n,y + n);
                add(y + n,x + n);
            }
        }
    }
    
    for(int i = 0;i < n;i++) {
    
    
        if(!dfn[i]) tarjan(i);
    }
    
    for(int i = 0;i < n;i++) {
    
    
        if(scc[i] == scc[i + n]) {
    
    
            printf("NO\n");
            return 0;
        }
    }
    
    printf("YES\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/109266305