1. 程式人生 > 實用技巧 >【POJ 3678】Katu Puzzle

【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;
}