您的位置:首页 > 其它

poj 2723 Get Luffy Out 2_SAT

2016-06-14 20:59 337 查看
题目大意

有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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: