wiki 2490 导弹拦截塔
2013-09-23 21:16
二分答案+匈牙利判断
对于每一个时间,我们重新建一张二分图,由于每个塔可能打多次,所以要拆点,
对于每个拆的点的可行飞行距离为(mid-t1)-(ll-1)*(t1+t2)*v,其中mid为二分的答案
ll为将当前的点拆成第几个点(因为拆的点的时间是不一样的),然后依次判断该点和
入侵者的距离是否小于,是则加边。
建完图之后判断是否存在完美匹配,存在则向下二分,否则向上二分。
//吐槽下,靠靠,t1的单位是秒,t2的单位是分钟。。。
代码只是过了数据,好多地方都可以优化。
比较弱,二分没有标程写的好,标程可以直接得到最后答案。
//By BLADEVIL
var
n, m, t2, v :longint;
t1 :real;
dis :array[0..100,0..100] of real;
ans :real;
pre, other, last :array[0..200100] of longint;
link :array[0..100] of longint;
flag :array[0..100] of boolean;
x1, x2, y1, y2 :array[0..100] of longint;
l :longint;
len :array[0..200100] of real;
procedure init;
var
i, j :longint;
begin
read(n,m,t1,t2,v);
for i:=1 to m do read(x2[i],y2[i]);
for i:=1 to n do read(x1[i],y1[i]);
t1:=t1/60;
for i:=1 to n do
for j:=1 to m do
dis[i,j]:=sqrt((x1[i]-x2[j])*(x1[i]-x2[j])+(y1[i]-y2[j])*(y1[i]-y2[j]));
end;
procedure connect(x,y:longint; z:real);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
len[l]:=z;
end;
function find(i:longint):boolean;
var
q, p :longint;
begin
q:=last[i];
while q<>0 do
begin
p:=other[q];
if (not flag[p]) then
begin
flag[p]:=true;
if (link[p]=0) or (find(link[p])) then
begin
link[p]:=i;
exit(true);
end;
end;
q:=pre[q];
end;
exit(false);
end;
procedure judge(low,high:real);
var
mid :real;
tot :longint;
i, j, ll :longint;
k :longint;
count :longint;
begin
if high<low then exit;
fillchar(last,sizeof(last),0);
fillchar(link,sizeof(link),0);
tot:=0;
l:=1;
mid:=(low+high)/2;
k:=trunc(((mid-t1)/(t1+t2))+1);
for i:=1 to n do
for ll:=1 to k do
begin
inc(tot);
for j:=1 to m do
if (((mid-t1)-(ll-1)*(t1+t2))*v)>=dis[i,j]
then connect(tot,j,dis[i,j]/v+(ll-1)*(t1+t2)+t1);
end;
count:=0;
for i:=1 to tot do
begin
fillchar(flag,sizeof(flag),false);
if find(i) then inc(count);
end;
if (high-low<1e-8) then
if count>=m then
begin
ans:=mid;
end else exit;
if count>=m then
begin
ans:=mid;
judge(low,mid-1e-8);
end else judge(mid+1e-8,high);
end;
procedure main;
begin
judge(1,30000);
writeln(ans:0:6);
end;
begin
init;
main;
end.