Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8335 | Accepted: 3073 |
Description
Katu Puzzle is presented as a directed graph G(V, E) 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 ≤ Xi ≤ 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:
|
|
|
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 a (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
题意:有n个点,每两个点可以通过三种运算符得到这两点之间的边边权。
分析:每个点有两种可选的状态0或1,显然这是2-sat 问题,现在就是建图了。
注意:
1、AND: a AND b=1,说明a和b必须是1,为了找出矛盾,那么就让a和b选0的时候无解,所以连接 a->a+n,b->b+n,也是为了建反边后,top序先选择a,b。
2、有些边不能建双向边,比如i&j=0,只能说明如果a为1,b必须为0,不能说明如果b为0,a 必须为1,还可以为0.
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MAX 1005
#define mod 10000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
int v,next;
}e[MAX*MAX];
int tot,head[MAX];
void addedge(int u,int v) {
e[tot].v=v;
e[tot].next=head[u];
head[u]=tot++;
}
int tarjan_clock=0,scc_cnt=0;
int pre[MAX],sccno[MAX],lowlink[MAX];
stack<int> sk;
void Tarjan(int u) {
pre[u]=lowlink[u]=++tarjan_clock;
sk.push(u);
for(int i=head[u]; i!=-1; i=e[i].next) {
int v=e[i].v;
if(!pre[v]) {
Tarjan(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if(!sccno[v])
lowlink[u]=min(lowlink[u],pre[v]);
}
if(lowlink[u]==pre[u]) {
scc_cnt++;
while(1) {
int x=sk.top();
sk.pop();
sccno[x]=scc_cnt;
if(x==u)
break;
}
}
}
void find_scc(int n) {
tarjan_clock=scc_cnt=0;
CLR(sccno,0);
CLR(pre,0);
for(int i=1; i<=n; i++) {
if(!pre[i]) Tarjan(i);
}
}
void init() {
tot=0;
CLR(head,-1);
}
int main() {
int n,m,u,v,w;
char s[10];
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
scanf("%d%d%d %s",&u,&v,&w,s);
u++,v++;
if(s[0]=='A') {
if(w) {
addedge(u+n,v+n);
addedge(v+n,u+n);
addedge(u,u+n);
addedge(v,v+n);
}
else {
addedge(u+n,v);
addedge(v+n,u);
}
} else if(s[0]=='O') {
if(w) {
addedge(u,v+n);
addedge(v,u+n);
} else {
addedge(u+n,u);
addedge(v+n,v);
addedge(u,v);
addedge(v,u);
}
}else {
if(w) {
addedge(u,v+n);
addedge(v,u+n);
addedge(u+n,v);
addedge(v+n,u);
} else {
addedge(u,v);
addedge(v,u);
addedge(u+n,v+n);
addedge(v+n,u+n);
}
}
}
find_scc(2*n);
for(int i=1;i<=n;i++)
if(sccno[i]==sccno[i+n]) {
printf("NO\n");
return 0;
}
printf("YES\n");
return 0;
}