Description
Katu Puzzle ispresented as a directed graph G(V, E) with eachedge e(a, b) labeled by a boolean operator op (oneof AND, OR, XOR) and an integer c (0 ≤ c ≤1). One Katu is solvable if one can find each vertex Vi avalue 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 rulesare:
|
|
|
Given a Katu Puzzle,your task is to determine whether it is solvable.
Input
The first linecontains 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 andan operator op each, describing the edges.
Output
Output a linecontaining "YES" or "NO".
SampleInput
4 4
0 1 1 AND
1 2 1 OR
3 2 0 AND
3 0 0 XOR
SampleOutput
YES
Hint
X0 = 1, X1 =1, X2 = 0, X3 = 1
题目大意:给m组关系(例如:0 1 1 AND,表示在B={b0,b1,……,bn}中,b0 and b1=1),问是否有方案使得所有条件成立。
分析:下面我们先把每个变量拆成两个点,一个表示值为true,一个表示值为false。然后定义连边(i,j),表示选了i必须选j。显然最后如果表示i为true和表示i为false的两个点在同一个强连通分量,那么就无解,否则就有解。按照逆拓扑序,逐个确定对应变量的值,最终就可以得到一个可行解。
对于本题,设i表示该变量为false,i’表示该变量为true。
i and j=1-------------->add(i,i') add(j,j')
i and j=0-------------->add(i',j) add(j',i)
i or j=1---------------->add(i,j') add(j',i)
i or j=0---------------->add(i',i) add(j',j)
i xor j=1--------------->add(i',j) add(j',i) add(i,j') add(j,i')
i xor j=0---------------> add(i,j) add(i',j') add(j,i) add(j',i')
因为只需要求是否有解,所以我用的是tarjan。
程序:
const
maxn=2005;
maxm=4000005;
type
node=record
x,y,next:longint;
end;
var
n,m,e,cnt,d,num,tot:longint;
ls,dfn,low,belong,stack:array [1..maxn] of longint;
g:array [1..maxm] of node;
instack:array [1..maxn] of boolean;
procedure add(x,y:longint);
begin
inc(e);
g[e].x:=x;
g[e].y:=y;
g[e].next:=ls[x];
ls[x]:=e;
end;
procedure init;
var
i,j,x,y,ans:longint;
ch:char;
begin
read(n,m);
e:=0;
for i:=1 to m do
begin
read(x,y,ans);
inc(x); inc(y);
repeat
read(ch);
until ch<>' ';
readln;
if ch='A' then
if ans=1 then
begin
add(x,x+n);
add(y,y+n);
end
else
begin
add(x+n,y);
add(y+n,x);
end;
if ch='O' then
if ans=1 then
begin
add(x,y+n);
add(y,x+n);
end
else
begin
add(x+n,x);
add(y+n,y);
end;
if ch='X' then
if ans=1 then
begin
add(x,y+n);
add(x+n,y);
add(y,x+n);
add(y+n,x);
end
else
begin
add(x,y);
add(y,x);
add(x+n,y+n);
add(y+n,x+n);
end;
end;
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x)
else exit(y);
end;
procedure tarjan(i:longint);
var j,t:longint;
begin
inc(d);
dfn[i]:=d;
low[i]:=d;
inc(tot);
stack[tot]:=i;
t:=ls[i];
instack[i]:=true;
while t>0 do
begin
j:=g[t].y;
if dfn[j]=0 then
begin
tarjan(j);
low[i]:=min(low[i],low[j]);
end
else
if instack[j] then
low[i]:=min(low[i],dfn[j]);
t:=g[t].next;
end;
if low[i]=dfn[i] then
begin
inc(num);
repeat
j:=stack[tot];
instack[j]:=false;
dec(tot);
belong[j]:=num;
until i=j;
end;
end;
procedure solve;
var i:longint;
begin
d:=0; num:=0;
fillchar(dfn,sizeof(dfn),0);
for i:=1 to n*2 do
if dfn[i]=0 then
tarjan(i);
end;
procedure output;
var i:longint;
begin
for i:=1 to n do
if belong[i]=belong[i+n] then
begin writeln('NO'); halt; end;
writeln('YES');
end;
begin
init;
solve;
output;
end.