题目: | Building roads | |
来源: | Pku 2749 | |
题目大意: | 有两个中转站,和N个点。每个点要么连到1号中转站,要么连到2号中转站。给出一 些限制信息,即哪两个点必须连到一个中转站上,哪两个点必须不能连到一个中转站 上,求任意两个中转站间最大的距离最小。 | |
数据范围: | 2 <= N <= 500, 0 <= A <= 1000, 0 <= B <= 1000,坐标[-1000000, 1000000] | |
样例: | 4 1 1 12750 28546 15361 32055 6706 3887 10754 8166 12668 19380 15788 16059 3 4 2 3 | 53246 |
做题思路: | 做这道题发现大数组+记录型的变量直接赋值,直接TLE 把X点连到1号中转站上设为I点,连到2号中转站上设为I'点。 | |
知识点: | 2-sat、kosaraju、构图 |
type
act=record
y,next:longint;
end;
var
a1,a2:array[0..1000000]of act;
b:array[0..500,0..500]of boolean;
first1,first2,q,f,dist1,dist2,f1,f2:array[0..10000]oflongint;
tot1,tot2,n,d,ans,time,p1,p2:longint;
//============================================================
procedure build1(x,y:longint);
begin
inc(tot1);
a1[tot1].y:=y;
a1[tot1].next:=first1[x];
first1[x]:=tot1;
end;
//=====================================================================
procedure build2(x,y:longint);
begin
inc(tot2);
a2[tot2].y:=y;
a2[tot2].next:=first2[x];
first2[x]:=tot2;
end;
//===================================================================
procedure init;
var
i,x1,x2,y1,y2,x,y,a,bi,j:longint;
begin
fillchar(first1,sizeof(first1),0);
fillchar(first2,sizeof(first2),0);
fillchar(b,sizeof(b),false);
tot1:=0;tot2:=0;
readln(n,a,bi);
readln(x1,y1,x2,y2);
d:=abs(x1-x2)+abs(y1-y2);
fori:=1 to n do
begin
readln(x,y);
dist1[i]:=abs(x-x1)+abs(y-y1);
dist2[i]:=abs(x-x2)+abs(y-y2);
end;
fori:=1 to a do
begin
readln(x,y);
b[x,y]:=true;b[y,x]:=true;
build1(x*2,y*2-1);build2(y*2-1,x*2);
build1(y*2,x*2-1);build2(x*2-1,y*2);
build1(x*2-1,y*2);build2(y*2,x*2-1);
build1(y*2-1,x*2);build2(x*2,y*2-1);
end;
fori:=1 to bi do
begin
readln(x,y);
b[x,y]:=true;b[y,x]:=true;
build1(x*2,y*2);build2(y*2,x*2);
build1(y*2,x*2);build2(x*2,y*2);
build1(x*2-1,y*2-1);build2(y*2-1,x*2-1);
build1(y*2-1,x*2-1);build2(x*2-1,y*2-1);
end;
p1:=tot1;p2:=tot2;
f1:=first1;f2:=first2;
end;
//============================================================
procedure dfs1(x:longint);
var
t:longint;
begin
f[x]:=1;
t:=first1[x];
whilet>0 do
begin
iff[a1[t].y]=0 then dfs1(a1[t].y);
t:=a1[t].next;
end;
inc(time);
q[time]:=x;
end;
//================================================================
procedure dfs2(x:longint);
var
t:longint;
begin
f[x]:=time;
t:=first2[x];
whilet>0 do
begin
iff[a2[t].y]=0 then dfs2(a2[t].y);
t:=a2[t].next;
end;
end;
//==============================================================
function kosaraju(x:longint):boolean;
var
i,j:longint;
begin
tot1:=p1;tot2:=p2;{<注意每次二分判定是要还原边表>}
first1:=f1;first2:=f2;
fori:=1 to n-1 do
forj:=i+1 to n do
ifnot b[i,j] then
begin
ifdist1[i]+dist1[j]>x then
begin
build1(i*2-1,j*2);build2(j*2,i*2-1);
build1(j*2-1,i*2);build2(i*2,j*2-1);
end;
ifdist2[i]+dist2[j]>x then
begin
build1(i*2,j*2-1);build2(j*2-1,i*2);
build1(j*2,i*2-1);build2(i*2-1,j*2);
end;
ifdist1[i]+d+dist2[j]>x then
begin
build1(i*2-1,j*2-1);build2(j*2-1,i*2-1);
build1(j*2,i*2);build2(i*2,j*2);
end;
ifdist1[j]+d+dist2[i]>x then
begin
build1(j*2-1,i*2-1);build2(i*2-1,j*2-1);
build1(i*2,j*2);build2(j*2,i*2);
end;
end;
fillchar(f,sizeof(f),0);
fillchar(q,sizeof(q),0);
time:=0;
fori:=1 to 2*n do
iff[i]=0 then dfs1(i);
fillchar(f,sizeof(f),0);
time:=0;
fori:=2*n downto 1 do
iff[q[i]]=0 then
begin
inc(time);
dfs2(q[i]);
end;
fori:=1 to n do
iff[i*2]=f[i*2-1] then exit(false);
exit(true);
end;
//======================================================================
procedure main;
var
l,r:longint;
begin
l:=0;r:=4000001;{<最大距离4000000超了就输出-1>}
whilel<r do
ifkosaraju((l+r)shr 1) then r:=(l+r)shr 1
elsel:=(l+r)shr 1+1;
ifl>4000000 then writeln('-1') else
writeln(l);
end;
//=================================================================
begin
init;
main;
end.
题目来源:
http://poj.org/problem?id=2749