POJ 3678 Katu Puzzle
Katu Puzzle
题意:
有n个变量(每个变量只能是0或者1),m个等式,每个等式形如$x_i \ op \ x_j = c, \ op \in["and","or","xor"],c \in [0,1]$,问能否给n个变量赋值,满足所有等式。
分析:
2-sat问题。
注意一下a&b=1的时候,要求a,b都为1,那么就是说明“如果a为0,那么a为1”,所以连边a->a+n。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 2005; struct Edge{ int to, nxt; } e[2000005]; int head[N], dfn[N], low[N], sk[N], bel[N], En, Index, top, tot; bool vis[N]; inline void add(int u,int v) { ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En; } void tarjan(int u) { dfn[u] = low[u] = ++Index; sk[++top] = u, vis[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (vis[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { ++tot; do { vis[sk[top]] = 0; bel[sk[top]] = tot; top --; } while (sk[top + 1] != u); } } int main() { // freopen("1.txt", "r", stdin); int n = read(), m = read(); char op[10]; for (int i = 1; i <= m; ++i) { int a = read(), b = read(), c = read();scanf("%s",op); a ++, b ++; if (op[0] == 'A') { if (c == 0) add(a + n, b), add(b + n, a); else add(a, a + n), add(b, b + n); } else if (op[0] == 'O') { if (c == 0) add(a + n, a), add(b + n, b); else add(a, b + n), add(b, a + n); } else if (op[0] == 'X') { if (c == 0) add(a, b), add(b + n, a + n), add(b, a), add(a + n, b + n); else add(a, b + n), add(b, a + n), add(b + n, a), add(a + n, b); } } for (int i = 1; i <= n + n; ++i) if (!dfn[i]) tarjan(i); for (int i = 1; i <= n; ++i) { if (bel[i] == bel[i + n]) { puts("NO"); return 0; } } puts("YES"); return 0; }