1579 泽泽在巴西

题目

比赛开始,泽泽队率先发球。泽泽观察了四周,想怎么才能用最短的时间射门呢?
  射门的时间为距离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)((x1x0)2(y1y0)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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值