题意:有n个牛棚, 还有两个中转站S1和S2, S1和S2用一条路连接起来。 为了使得任意牛棚两个都可以有道路联通,现在要让每个牛棚都连接一条路到S1或者S2。
有a对牛棚互相有仇恨,所以不能让他们的路连接到同一个中转站。还有b对牛棚互相喜欢,所以他们的路必须连到同一个中专站。
道路的长度是两点的曼哈顿距离。
问最小的任意两牛棚间的距离中的最大值是多少?
分析:首先二分最大距离,然后建图:
一、若两点的某种选择的连接方式使得这两点间的距离大于最大距离则矛盾,然后加边。
二、根据仇恨情况和喜欢情况加边。
不知道为什么在poj上AC了在hdu上却WA了。表示不能理解咯。
代码:
var e,n,a1,b1,x1,x2,y1,y2,tot,f1:longint; x,y:array[1..500] of longint; a,b:array[1..1000,1..2] of longint; side:array[1..1000000] of record x,y,next:longint; end; belong,last,f:array[1..2000] of longint; v:array[1..2000] of boolean; 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:longint; begin readln(n,a1,b1); readln(x1,y1,x2,y2); for i:=1 to n do readln(x[i],y[i]); for i:=1 to a1 do readln(a[i,1],a[i,2]); for i:=1 to b1 do readln(b[i,1],b[i,2]); end; procedure build(mid:longint); var s,i,j:longint; begin e:=0; fillchar(last,sizeof(last),0); for i:=1 to a1 do begin add(a[i,1],a[i,2]+n); add(a[i,1]+n,a[i,2]); add(a[i,2],a[i,1]+n); add(a[i,2]+n,a[i,1]); end; for i:=1 to b1 do begin add(b[i,1],b[i,2]); add(b[i,1]+n,b[i,2]+n); add(b[i,2],b[i,1]); add(b[i,2]+n,b[i,1]+n); end; s:=abs(x1-x2)+abs(y1-y2); for i:=1 to n-1 do for j:=i+1 to n do begin if abs(x[i]-x1)+abs(y[i]-y1)+abs(x[j]-x1)+abs(y[j]-y1)>mid then begin add(i,j+n); add(j,i+n); end; if abs(x[i]-x2)+abs(y[i]-y2)+abs(x[j]-x2)+abs(y[j]-y2)>mid then begin add(i+n,j); add(j+n,i); end; if abs(x[i]-x1)+abs(y[i]-y1)+abs(x[j]-x2)+abs(y[j]-y2)+s>mid then begin add(i,j); add(j+n,i+n); end; if abs(x[i]-x2)+abs(y[i]-y2)+abs(x[j]-x1)+abs(y[j]-y1)+s>mid then begin add(i+n,j+n); add(j,i); end; end; end; procedure dfs(x:longint); var i:longint; begin v[x]:=false; i:=last[x]; while i>0 do with side[i] do begin if v[y] then dfs(y); i:=next; end; if tot=0 then begin inc(f1); f[f1]:=x; end else belong[x]:=tot; end; procedure kosaraju; var i:longint; begin tot:=0; f1:=0; fillchar(v,sizeof(v),true); for i:=1 to n*2 do if v[i] then dfs(i); fillchar(last,sizeof(last),0); for i:=1 to e do add(side[i].y,side[i].x); fillchar(v,sizeof(v),true); for i:=n*2 downto 1 do if v[f[i]] then begin inc(tot); dfs(f[i]); end; end; procedure main; var l,r,mid,ans,i:longint; flag:boolean; begin l:=0; r:=4000000; ans:=maxlongint; while l<=r do begin mid:=(l+r) div 2; build(mid); kosaraju; 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; r:=mid-1; end else l:=mid+1; end; if ans=maxlongint then ans:=-1; writeln(ans); end; begin init; main; end.