poj 2723 Get Luffy Out 2-SAT

题意:有2n把钥匙和m扇门。这2n把钥匙被分成若干对,每对只能选一把来使用。每扇门可以被指定的两把钥匙打开(只用其中一把)。只有按顺序打开前i-1扇门才能打开第i扇门。问最多可以打开多少扇门。

 

分析:首先二分答案,然后分析到每扇门就相当于一个or运算,然后建图:

i表示选第i对钥匙的前一把,i+n表示选第i对钥匙的后一把,next(i)表示和钥匙i对应的另一把钥匙。

假设某扇门需要钥匙i和j则连边next(i)->j  next(j)->i

然后跑强连通分量。

若有满足的i使得i和next(i)在同一强连通分量,则不满足条件,反之则满足。

 

代码:

var
  n,m,l,r,ans,mid,i,tot,sum,d,e:longint;
  flag:boolean;
  x,y,p,q,stack,low,dfn,belong,last,num:array[1..3000] of longint;
  f:array[1..3000] of boolean;
  side:array[1..100000] of record
    x,y,next:longint;
  end;

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;

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);
  low[x]:=d;
  dfn[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 dfn[x]=low[x] then
  begin
    inc(sum);
    repeat
      i:=stack[tot];
      f[i]:=false;
      dec(tot);
      belong[i]:=sum;
    until i=x;
  end;
end;

function next(x:longint):longint;
begin
  if x>n then exit(x-n)
         else exit(x+n);
end;

begin
  readln(n,m);
  while n+m>0 do
  begin
    for i:=1 to n do
    begin
      readln(x[i],y[i]);
      inc(x[i]);
      inc(y[i]);
      num[x[i]]:=i;
      num[y[i]]:=i+n;
    end;
    for i:=1 to m do
    begin
      readln(p[i],q[i]);
      inc(p[i]);
      inc(q[i]);
      p[i]:=num[p[i]];
      q[i]:=num[q[i]];
    end;
    l:=0;
    r:=m;
    ans:=0;
    while l<=r do
    begin
      mid:=(l+r) div 2;
      e:=0;
      fillchar(last,sizeof(last),0);
      for i:=1 to mid do
      begin
        add(next(p[i]),q[i]);
        add(next(q[i]),p[i]);
      end;
      fillchar(low,sizeof(low),0);
      fillchar(dfn,sizeof(dfn),0);
      fillchar(f,sizeof(f),false);
      d:=0;
      tot:=0;
      sum:=0;
      for i:=1 to n*2 do
        if dfn[i]=0 then dfs(i);
      flag:=true;
      for i:=1 to n do
        if belong[i]=belong[i+n] then
        begin
          flag:=false;
          break;
        end;
      if flag
        then begin
               if mid>ans then ans:=mid;
               l:=mid+1;
             end
        else r:=mid-1;
    end;
    writeln(ans);
    readln(n,m);
  end;
end.



 

你可能感兴趣的:(poj 2723 Get Luffy Out 2-SAT)