题目
比赛开始,泽泽队率先发球。泽泽观察了四周,想怎么才能用最短的时间射门呢?
射门的时间为距离2,而传球的时间是距离1。所以泽泽想找一条用时最少的射门路径,来打败足球流氓。
足球流氓当然不会袖手旁观,他们会拦截。当泽泽队伍中的传球人、被传球人之间有某足球流氓并且他们在同一直线上时,传球不会成功,即不能这样传球。比如A(1,2)想传球给B(7,8),中间有个足球流氓C(3,4),则他们在同一直线,传球不成功。射门不受足球流氓影响。
题解
枚举所有点之间的路径,如果没有足球流氓就连一条边,边权即两点间距离。
然后SPFA跑一边
足球流氓判断方法
叉积为0,且足球流氓在两点中间
两点间距离
√((x1−x0)2−(y1−y0)2) √((x1-x0)^2-(y1-y0)^2)√((x1−x0)2−(y1−y0)2)
注意
射门不受足球流氓影响,且时间要*2
放边的数据不要太小,至少200000
时间复杂度
O(n3)O(n^3)O(n3)
代码
type
rec=record
x,y,ne:longint;
w:real;
end;
var
x0,y0,n,mm,i,j,k,l,t:longint;
e:array[1..500000]of rec;
a,b:array[1..500,1..2]of longint;
d:array[1..500]of real;
state,v:array[1..500000]of longint;
ls:array[1..500]of longint;
function m(x0,y0,x1,y1,x2,y2:longint):longint;
var
x,y,xx,yy:longint;
begin
x:=x0;xx:=x1;
if x0<x1 then begin x:=x1;xx:=x0;end;
y:=y0;yy:=y1;
if y0<y1 then begin y:=y1;yy:=y0;end;
if (x2>x)or(x2<xx)or(y2>y)or(y2<yy) then exit(1) else
m:=((x2-x0)*(y1-y0))-((x1-x0)*(y2-y0));
end;
procedure spfa;
var
h,t,x,y,l:longint;
w:real;
begin
h:=0;t:=1;state[t]:=1;
d[1]:=0;
while h<t do
begin
inc(h);
l:=ls[state[h]];
while l>0 do
begin
x:=e[l].x;y:=e[l].y;w:=e[l].w;
if d[x]+w<d[y] then
begin
d[y]:=d[x]+w;
if (v[y]=0)and(y<>n+1) then
begin
inc(t);
state[t]:=y;
v[y]:=1;
end;
end;
l:=e[l].ne;
end;
v[state[h]]:=0;
end;
end;
begin
readln(x0,y0,n,mm);
fillchar(d,sizeof(d),$7f);
for i:=1 to n do
readln(a[i,1],a[i,2]);
for i:=1 to mm do
readln(b[i,1],b[i,2]);
for i:=1 to n do
for j:=1 to n do
if i<>j then
begin
l:=0;
for k:=1 to mm do
if m(a[i,1],a[i,2],a[j,1],a[j,2],b[k,1],b[k,2])=0 then
begin l:=1;break;end;
if l=0 then
begin
inc(t);
e[t].x:=i;e[t].y:=j;
e[t].w:=sqrt(sqr(a[i,1]-a[j,1])+sqr(a[i,2]-a[j,2]));
e[t].ne:=ls[i];
ls[i]:=t;
end;
end;
for i:=1 to n do
begin
inc(t);
e[t].x:=i;e[t].y:=n+1;
e[t].w:=sqrt(sqr(a[i,1]-x0)+sqr(a[i,2]-y0))*2;
e[t].ne:=ls[i];
ls[i]:=t;
end;
spfa;
writeln(d[n+1]:0:0);
end.


1050

被折叠的 条评论
为什么被折叠?



