poj 2723 Get Luffy Out 2_SAT
题目大意
有m层楼,从一层到m层,要进入每层都要打开位于该层的两道门中的至少一道。门锁有2n种,每个门锁为2n种中的一种,可以重复。有2n把钥匙,分别对应2n种锁,但是钥匙两两一组,共n组,每组只能选一个来开门,被选中的可以多次使用,另一个一次都不能用。问最多能上多少层。
分析
对于每组钥匙,只能二取一,所以是2-SAT模型。
建图:某层有x,y两种锁,x的钥匙a与钥匙b一组,y的要是c与钥匙d一组。如果在某次选了钥匙b,那么本层的x将无法被打开,只能开y,就必须选钥匙c,不能选钥匙d(因为钥匙d解不开y)。链接(b,c)和(d,a)。
答案二分
代码
type arr=record x,y,next:longint; end; var a:array[1..2000000] of arr; f:array[1..3000] of boolean; ls,zan,g:array[1..3000] of longint; dfn,low,num1,x1,y1:array[1..3000] of longint; tot,sum:longint; n,m:longint; i,j,k:longint; r,l,mid:longint; ans:longint; e,d:longint; x,y:longint; procedure add(x,y:longint); begin inc(e); a[e].x:=x; a[e].y:=y; a[e].next:=ls[x]; ls[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); dfn[x]:=d; low[x]:=d; inc(tot); zan[tot]:=x; f[x]:=true; i:=ls[x]; while i>0 do with a[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:=zan[tot]; dec(tot); f[i]:=false; g[i]:=sum; until i=x; end; end; procedure tarjan; var i:longint; begin for i:=1 to n*2 do if dfn[i]=0 then dfs(i); end; function work:boolean; var i:longint; begin for i:=1 to n do if g[i]=g[i+n] then begin work:=false; exit; end; exit(true); end; function ban(x:longint):longint; begin if x>n then exit(x-n); exit(x+n); end; procedure init; var i,j,k:longint; begin fillchar(x1,sizeof(x1),0); fillchar(y1,sizeof(y1),0); fillchar(num1,sizeof(num1),0); for i:=1 to n do begin readln(x,y); x:=x+1; y:=y+1; num1[x]:=i; num1[y]:=i+n; end; for i:=1 to m do begin readln(x,y); x:=x+1; y:=y+1; x1[i]:=num1[x]; y1[i]:=num1[y]; end; end; begin readln(n,m); while (n<>0) or (m<>0) do begin init; l:=0; r:=m; ans:=0; while l<=r do begin mid:=(l+r) div 2; fillchar(dfn,sizeof(dfn),0); fillchar(low,sizeof(low),0); fillchar(ls,sizeof(ls),0); fillchar(g,sizeof(g),0); fillchar(zan,sizeof(zan),0); fillchar(f,sizeof(f),0); e:=0; d:=0; tot:=0; sum:=0; for i:=1 to mid do begin add(ban(x1[i]),y1[i]); add(ban(y1[i]),x1[i]); end; tarjan; if work then begin l:=mid+1; if ans<mid then ans:=mid; end else r:=mid-1; end; writeln(ans); readln(n,m); end; end.