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