poj 3678 Katu Puzzle 2-SAT

题意:给定n个布尔型变量,以及m个限制,限制有三种类型,AND,OR,XOR。分别表示两个变量进行这些运算的值。每个变量只能取0或1.问是否有一种情况满足所有条件的限制。


分析:

对于本题,设i表示该变量为falsei’表示该变量为true

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')

连一条边i->j表示若选i则必选j。

然后求一次强联通分量,若有i、i'在同一强联通分量内则无满足条件,反之则有。

详细证明略。


代码:

var
  tot,sum,n,e,m,d:longint;
  side:array[1..5000000] of record
    x,y,next:longint;
  end;
  f:array[1..3000] of boolean;
  last,stack,belong,dfn,low:array[1..3000] of longint;

procedure add(x,y:longint);
begin
  inc(e);
  side[e].x:=x;
  side[e].y:=y;
  side[e].next:=last[x];
  last[x]:=e;
end;

procedure init;
var
  i,x,y,z:longint;
  c:char;
begin
  readln(n,m);
  for i:=1 to m do
  begin
    read(x,y,z);
    inc(x);
    inc(y);
    read(c);
    while c=' ' do read(c);
    readln;
    if c='A' then
      if z=1
        then begin
               add(x,x+n);
               add(y,y+n);
             end
        else begin
               add(x+n,y);
               add(y+n,x);
             end;
    if c='O' then
      if z=1
        then begin
               add(x,y+n);
               add(y,x+n);
             end
        else begin
               add(x+n,x);
               add(y+n,y);
             end;
    if c='X' then
      if z=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(x+n,y+n);
               add(y,x);
               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 dfs(x:longint);
var
  i:longint;
begin
  inc(d);
  dfn[x]:=d;
  low[x]:=d;
  inc(tot);
  stack[tot]:=x;
  f[x]:=true;
  i:=last[x];
  while i>0 do
    with side[i] do
    begin
      if dfn[y]=0
        then begin
               dfs(y);
               low[x]:=min(low[x],low[y]);
             end
        else if f[y] then low[x]:=min(low[x],dfn[y]);
      i:=next;
    end;
  if low[x]=dfn[x] then
  begin
    inc(sum);
    repeat
      i:=stack[tot];
      dec(tot);
      f[i]:=false;
      belong[i]:=sum;
    until i=x;
  end;
end;

procedure tarjan;
var
  i:longint;
begin
  fillchar(f,sizeof(f),false);
  for i:=1 to n*2 do
    if dfn[i]=0 then dfs(i);
end;

procedure work;
var
  i:longint;
begin
  for i:=1 to n do
    if belong[i]=belong[i+n] then
    begin
      writeln('NO');
      exit;
    end;
  writeln('YES');
end;

begin
  init;
  tarjan;
  work;
end.


你可能感兴趣的:(poj 3678 Katu Puzzle 2-SAT)