poj3678-Katu Puzzle

\(n\)个bool变量和\(m\)条限制,每条限制为a op b=c的形式,其中op为逻辑运算,问是否存在合法解。

分析

这一类问题叫做2-SAT问题,有很多个两种取值的变量,其中有一些限制条件。2-SAT问题我们采用建模的方式,如果\(a\)选就一定要选\(b\),那么连有向边\((a,b)\)。2-SAT问题有解的条件就是\(a\)\(!a\)不在同一个强连通分量中,也就是说不产生矛盾。

几个基本逻辑运算的连边如下,其他的都可以转化为这几种:

  • a=true,\(!a\to a\)
  • a=false,\(a\to !a\)
  • a or b=true,\(!a\to b,!b\to a\)
  • a or b=false,等价于\(a=false,b=false\)
  • a and b=true,等价于\(a=true,b=true\)
  • a and b=false,\(a\to !b,b\to !a\)
  • a xor b=true,\(a\to !b,!a\to b,b\to !a,!b\to a\)
  • a xor b=false,\(a\to b,!a\to !b,b\to a,!b\to !a\)
  • a=b,等价于a xor b=false
  • \(a\ne b\),等价于a xor b=true

这道题就这样做完啦。

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int read() {
	int x=0,f=1;
	char c=getchar();
	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
const int maxn=2e3+10;
const int maxm=4e6+10;
int dfn[maxn],low[maxn],dft=0,id[maxn],sta[maxn],top=0,col=0;
bool ins[maxn];
struct edge {
	int v,nxt;
};
struct graph {
	edge e[maxm];
	int h[maxn],tot;
	graph ():tot(0) {}
	void add(int u,int v) {
		e[++tot]=(edge){v,h[u]};
		h[u]=tot;
	}
	void Tarjan(int x) {
		dfn[x]=low[x]=++dft;
		sta[++top]=x;
		ins[x]=true;
		for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!dfn[v]) {
			Tarjan(v);
			low[x]=min(low[x],low[v]);
		} else if (ins[v]) low[x]=min(low[x],dfn[v]);
		if (low[x]==dfn[x]) {
			++col;
			do id[sta[top--]]=col; while (sta[top+1]!=x);
		}
		ins[x]=false;
	}
	bool run(int n) {
		for (int i=1;i<=n;++i) if (id[i]==id[n+i]) return false;
		return true;
	}
} A;
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
#endif
	int n=read(),m=read();
	for (int i=1;i<=m;++i) {
		int x=read()+1,y=read()+1,z=read();
		static char op[8];
		scanf("%s",op);
		if (op[0]=='A' && z) A.add(x+n,x),A.add(y+n,y); else
		if (op[0]=='A' && !z) A.add(x,y+n),A.add(y,x+n); else
		if (op[0]=='O' && z) A.add(x+n,y),A.add(y+n,x); else
		if (op[0]=='O' && !z) A.add(x,x+n),A.add(y,y+n); else 
		if (op[0]=='X' && z) A.add(x,y+n),A.add(x+n,y),A.add(y,x+n),A.add(y+n,x); else 
		if (op[0]=='X' && !z) A.add(x,y),A.add(x+n,y+n),A.add(y,x),A.add(y+n,x+n);
	}
	for (int i=1;i<=(n<<1);++i) if (!id[i]) A.Tarjan(i);
	puts(A.run(n)?"YES":"NO");
	return 0;
}
posted @ 2017-04-21 08:12  permui  阅读(202)  评论(0编辑  收藏  举报