【POJ 3678】Katu Puzzle
题目
题目链接: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;
}