【POJ 3678】Katu Puzzle
阿新 • • 發佈:2020-10-07
題目
題目連結:http://poj.org/problem?id=3678
有 \(n\) 個變數,每個可以取 \(0\) 或者 \(1\),再給出 \(m\) 組關係,每組關係都是兩個變數進行運算可以得到的結果,運算有 AND OR XOR 三種,問能否根據這些關係,判斷每個變數的取值。
思路
分類討論當運算為 AND OR XOR 時應有的關係,2-sat 即可。
時間複雜度 \(O(n+m)\)。
程式碼
#include <stack> #include <cstdio> #include <cctype> #include <string> #include <cstring> #include <algorithm> using namespace std; const int N=3000010; int n,m,tot,cnt,head[N],dfn[N],low[N],col[N],ans[N]; bool vis[N]; stack<int> st; struct Rode { int u,v,d; char ch[5]; }r[N]; struct edge { int next,to; }e[N*4]; int read() { int d=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar(); return d; } void add(int from,int to) { e[++tot].to=to; e[tot].next=head[from]; head[from]=tot; } void addedge(int i) { int u=r[i].u,v=r[i].v,d=r[i].d; if (r[i].ch[0]=='O') { if (d==0) add(u+n,u),add(v+n,v); if (d==1) add(u,v+n),add(v,u+n); } if (r[i].ch[0]=='A') { if (d==0) add(u+n,v),add(v+n,u); if (d==1) add(u,u+n),add(v,v+n); } if (r[i].ch[0]=='X') { if (d==0) add(u,v),add(v,u),add(u+n,v+n),add(v+n,u+n); if (d==1) add(u,v+n),add(v,u+n),add(u+n,v),add(v+n,u); } } void tarjan(int x) { dfn[x]=low[x]=++tot; st.push(x); vis[x]=1; for (int i=head[x];~i;i=e[i].next) { int v=e[i].to; if (!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if (vis[v]) low[x]=min(low[x],dfn[v]); } if (dfn[x]==low[x]) { cnt++; int y; do { y=st.top(); st.pop(); col[y]=cnt; vis[y]=0; } while (x!=y); } } int main() { memset(head,-1,sizeof(head)); n=read(); m=read(); for (int i=1;i<=m;i++) { r[i].u=read()+1; r[i].v=read()+1; r[i].d=read(); scanf("%s",r[i].ch); addedge(i); } tot=cnt=0; for (int i=1;i<=2*n;i++) if (!dfn[i]) tarjan(i); for (int i=1;i<=n;i++) if (col[i]==col[i+n]) return printf("NO"),0; printf("YES"); return 0; }