POJ 3678 Katu Puzzle

Description

给出一个关系,包括 And,Xor,Or 问是否存在解.

Sol

经典的2-SAT问题.

把每个值看成两个点,一个点代表选 (0) ,另一个代表选 (1) .

首先来看 Xor :

如果两个值异或起来为 (1) :那么连边 ((i_0,j_1),(i_1,j_0),(j_0,i_1),(j_1,i_0)) .

否则 连边 ((i_0,j_0),(i_1,j_1),(j_0,i_0),(j_1,i_1)) .

然后是 And.

如果两个值 And 起来为 (1) :连边 ((i_0,i_1),(j_0,j_1))

否则 连边 ((i_1,j_0),(j_1,i_0))

最后是 Or.

如果两个值 Or 起来为 (1) :连边 ((i_0,j_1),(j_1,i_0))

否则 连边 ((i_1,i_0),(j_1,j_0)) .

Tarjan 缩一下环判断一下两个点是否在一个环中就可以了.

Code

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;

const int N = 2005;

int n,m,cnt,cntb;
vector< int > g[N];
int d[N],b[N],ins[N];
int stk[N],top;

inline int in(int x=0,char ch=getchar()){ while(ch>'9' || ch<'0') ch=getchar();
	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; } 
void Add_Edge(int fr,int to) { g[fr].push_back(to); }
void Tarjan(int u,int fa) {
	int dfsn=++cnt;d[u]=cnt,ins[u]=1,stk[++top]=u;
	for(int i=0,v;i<(int)g[u].size();i++) {
		v=g[u][i];
		if(!d[v]) Tarjan(v,u);
		if(ins[v]) d[u]=min(d[u],d[v]);
	}if(dfsn==d[u]) {
		for(++cntb;stk[top]!=u;top--) {
			b[stk[top]]=cntb,ins[stk[top]]=0;
		}ins[stk[top]]=0,b[stk[top--]]=cntb;
	}
//	cout<<u<<":"<<dfsn<<" "<<d[u]<<endl;
}
int main() {
//	freopen("in.in","r",stdin);
	n=in(),m=in();
	char opt[50];
	for(int i=1;i<=m;i++) {
		int u=in(),v=in(),w=in();
		scanf("%s",opt);
		if(u>v) swap(u,v);
		if(opt[0]=='X') {
			if(w) {
				Add_Edge(u*2,v*2+1);
				Add_Edge(u*2+1,v*2);
				Add_Edge(v*2,u*2+1);
				Add_Edge(v*2+1,u*2);
			}else {
				Add_Edge(u*2,v*2);
				Add_Edge(v*2,u*2);
				Add_Edge(u*2+1,v*2+1);
				Add_Edge(v*2+1,u*2+1);
			}
		}else if(opt[0]=='A') {
			if(w) {
				Add_Edge(u*2,u*2+1);
				Add_Edge(v*2,v*2+1);
			}else {
				Add_Edge(u*2+1,v*2);
				Add_Edge(v*2+1,u*2);
			}
		}else {
			if(w) {
				Add_Edge(u*2,v*2+1);
				Add_Edge(v*2,u*2+1);
			}else {
				Add_Edge(u*2+1,u*2);
				Add_Edge(v*2+1,v*2);
			}
		}
	}
	for(int i=0;i<2*n;i++) if(!d[i]) Tarjan(i,i);
//	for(int i=0;i<2*n;i++) cout<<b[i]<<" ";cout<<endl;
	for(int i=0;i<2*n;i++) if(b[i]==b[i^1]) return puts("NO"),0;
	return puts("YES"),0;
}

  

原文地址:https://www.cnblogs.com/beiyuoi/p/6180480.html