POJ 3678 Katu Puzzle 2-SAT

Katu Puzzle
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 10965 Accepted: 4063

Description

Katu Puzzle is presented as a directed graph G(VE) with each edge e(a, b) labeled by a boolean operator op (one of AND, OR, XOR) and an integer c (0 ≤ c ≤ 1). One Katu is solvable if one can find each vertex Vi a value Xi (0 ≤ X≤ 1) such that for each edge e(a, b) labeled by op and c, the following formula holds:

 Xa op Xb = c

The calculating rules are:

AND01
000
101
OR01
001
111
XOR01
001
110

Given a Katu Puzzle, your task is to determine whether it is solvable.

Input

The first line contains two integers N (1 ≤ N ≤ 1000) and M,(0 ≤ M ≤ 1,000,000) indicating the number of vertices and edges.
The following M lines contain three integers (0 ≤ a < N), b(0 ≤ b < N), c and an operator op each, describing the edges.

Output

Output a line containing "YES" or "NO".

Sample Input

4 4
0 1 1 AND
1 2 1 OR
3 2 0 AND
3 0 0 XOR

Sample Output

YES

Hint

X 0 = 1,  X 1 = 1,  X 2 = 0,  X 3 = 1.

Source



一个图,每条边上有一个符号和一个结果,符号是and,or,xor当中的一种,结果是0或1。

要求给每个点分配0或1,使得每条边的两个端点的数值经过对应的符合运算后,结果与要求一致。


一个难点:如何构图使得a and b = 1, a or b = 0 实现。

构图方法:

(take a and b = 1 as an example)

此时两个点均不能取0.

连接a0,a1  b0,b1

这样做是为了导出矛盾。


其余的构图可以从代码中观察到。

奇数点表示0,偶数点表示1.


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=2005,maxk=2000005,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
int head[maxn];
int dfn[maxn],low[maxn],color[maxn];
bool inst[maxn];
int num=0,cnum=0;
stack<int> st;
char s[maxn];

struct Edge {
	int from,to,pre;
};
Edge edge[maxk];

void addedge(int from,int to) {
	edge[num]=(Edge){from,to,head[from]};
	head[from]=num++;
}

void tarjan(int now) {
	num++;
	dfn[now]=low[now]=num;
	inst[now]=1;
	st.push(now);
	for (int i=head[now];i!=-1;i=edge[i].pre) {
		int to=edge[i].to;
		if (!dfn[to]) {
			tarjan(to);
			low[now]=min(low[now],low[to]);
		}
		else if (inst[to]) 
		    low[now]=min(low[now],dfn[to]); 
	}
	if (dfn[now]==low[now]) {
		inst[now]=0;
		color[now]=++cnum;
		while (st.top()!=now) {
			color[st.top()]=cnum;
			inst[st.top()]=0;
			st.pop();
		}
		st.pop();
	}
}

int main() {
	int n,m,i,j,x,y,z;
	scanf("%d%d",&n,&m);
	num=0;
	memset(head,-1,sizeof(head));
	for (i=1;i<=m;i++) {
		scanf("%d%d%d%s",&x,&y,&z,s);
		x++;y++;
		if (s[0]=='O') {
			if (z==1) {
				addedge(x*2-1,y*2);
				addedge(y*2-1,x*2);
			} else {
				addedge(x*2,x*2-1);
				addedge(y*2,y*2-1);
				addedge(x*2-1,y*2-1);
				addedge(y*2-1,x*2-1);
			}
		}
		if (s[0]=='A') {
			if (z==0) {
				addedge(x*2,y*2-1);
				addedge(y*2,x*2-1);
			} else {
				addedge(x*2-1,x*2);
				addedge(y*2-1,y*2);
				addedge(x*2,y*2);
				addedge(y*2,x*2);
			}
		}
		if (s[0]=='X') {
			if (z==0) {
				addedge(x*2,y*2);
				addedge(x*2-1,y*2-1);
				addedge(y*2,x*2);
				addedge(y*2-1,x*2-1);
			} else {
				addedge(x*2,y*2-1);
				addedge(y*2,x*2-1);
				addedge(x*2-1,y*2);
				addedge(y*2-1,x*2);
			}
		}
	}
	num=0;
	mem0(dfn);mem0(low);mem0(color);mem0(inst);
	for (i=1;i<=2*n;i++) {
		if (!dfn[i]) tarjan(i);
	}
	for (i=1;i<=n*2;i+=2) {
		if (color[i]==color[i+1]) {
			printf("NO\n");return 0;
		}
	}
	printf("YES\n");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值