noi 2011 智能车比赛

http://61.187.179.132/JudgeOnline/problem.php?id=2433

图:http://221.192.240.123:8586/JudgeOnline/showproblem?problem_id=1668

 

好久没有编计算几何了啊。。。编地几欲吐血。。。差点被精度坑了。第八个点的最后两位是59,我输出60了。。。

 

想法是最短路,不过直接用递推实现。

首先,矩形可以抽象出n-1条公共边,那么图就只剩下这些边和两点。

然后,可以发现:如果两点不能直接相连,那么路径就必然经过若干条公共边的端点,这个可以用三角形两边之和大于第三边证。那么题目就相当于求一条从起点开始,经过若干个公共边上的端点,到达终点的最短路。

很明显,我们只要讨论起止点间的公共边。再来就是建图了。。求出公共边上端点之间的距离,当然,要判是否可行(用向量积。因为是整数,所以不用考虑eps...),不可行就赋成极大值。

 

错了好几次都是在求需要穿过哪些矩形公共边的范围上面。。。囧了。只要判断起止点是否在当前矩形内就可以的事我还想只用x坐标判断。。。自找麻烦。。。

 

AC CODE

 

program noi_2011_day1_car;
const maxn=9999999;
type li=record
          x,y1,y2:longint;
        end;
var line:array[1..2000] of li;
    l,next:array[1..100000] of longint;
    g:array[1..100000] of extended;
    tail:array[1..4000] of longint;
    x1,y1,x2,y2:array[1..2000] of longint;
    dis:array[1..4000] of double;
    be,en,tot,n,xs,xt,ys,yt:longint;
    v:double;
//============================================================================
procedure ins(x,y:longint; z:double);
begin
  inc(tot); l[tot]:=y; g[tot]:=z;
  next[tot]:=tail[x]; tail[x]:=tot;
end;
//============================================================================
function jiao(x1,y1,x2,y2,x3,y3,x4,y4:longint):boolean;    //向量积。
var s1,s2:int64;
begin
  s1:=(x3-x1)*(y2-y1)-(x2-x1)*(y3-y1);
  s2:=(x2-x1)*(y4-y1)-(x4-x1)*(y2-y1);
  if s1*s2>=0 then exit(true) else exit(false);
end;
//============================================================================
procedure init;
var i,tt:longint;
    flag:boolean;
begin
  readln(n);
  for i:=1 to n do
    readln(x1[i],y1[i],x2[i],y2[i]);
  readln(xs,ys,xt,yt); readln(v);
  if xt<xs then
  begin
    tt:=xs; xs:=xt; xt:=tt;
    tt:=ys; ys:=yt; yt:=tt;
  end; be:=0; en:=0;
  for i:=1 to n-1 do
  begin
    line[i].x:=x1[i+1];
    if y2[i]<y2[i+1] then line[i].y1:=y2[i] else line[i].y1:=y2[i+1];
    if y1[i]>y1[i+1] then line[i].y2:=y1[i] else line[i].y2:=y1[i+1];
    if (be=0) and (xs>=x1[i]) and (xs<=x2[i]) then
      if (ys>=y1[i]) and (ys<=y2[i]) then be:=i;
    if (en=0) and (xt>=x1[i]) and (xt<=x2[i]) then
      if (yt>=y1[i]) and (yt<=y2[i]) then en:=i-1;
  end; if en=0 then en:=n-1;    //这步没加在只有一个矩形的时候就囧了。。。
  flag:=true;
  if be>0 then
  for i:=be to en do
    if not(jiao(xs,ys,xt,yt,line[i].x,line[i].y1,line[i].x,line[i].y2)) then
    begin
      flag:=false;
      break;
    end;
  if flag then    //判断是否可以直接沿直线到达。
  begin
    writeln(sqrt(sqr(xs-xt)+sqr(ys-yt))/v:0:10);
    close(input); close(output);
    halt;
  end;
end;
//============================================================================
function drive(s,t,x1,y1,x2,y2:longint):double;    //判断(x1,y1)和(x2,y2)两点是否能直线连接(也就是经过它们之间所有的矩形公共边)。
var i:longint;
begin
  for i:=s to t do
    if not(jiao(x1,y1,x2,y2,line[i].x,line[i].y1,line[i].x,line[i].y2)) then
      exit(maxn);
  drive:=sqrt(sqr(x1-x2)+sqr(y1-y2));
end;
//============================================================================
procedure calculate;
var i,j:longint;
    tmp:double;
begin
  for i:=be to en-1 do
    for j:=i+1 to en do    //求n-1条公共边之间的距离。
    begin
      tmp:=drive(i+1,j-1,line[i].x,line[i].y1,line[j].x,line[j].y1);
      if tmp<>maxn then ins(i*2-1,j*2-1,tmp);
      tmp:=drive(i+1,j-1,line[i].x,line[i].y1,line[j].x,line[j].y2);
      if tmp<>maxn then ins(i*2-1,j*2,tmp);
      tmp:=drive(i+1,j-1,line[i].x,line[i].y2,line[j].x,line[j].y1);
      if tmp<>maxn then ins(i*2,j*2-1,tmp);
      tmp:=drive(i+1,j-1,line[i].x,line[i].y2,line[j].x,line[j].y2);
      if tmp<>maxn then ins(i*2,j*2,tmp);

    end;
end;
//============================================================================
procedure shortest;
var i,j,now:longint;
    ans,tmp:double;
begin
  for i:=be to en do
  begin
    dis[i*2-1]:=drive(be,i-1,xs,ys,line[i].x,line[i].y1);
    dis[i*2]:=drive(be,i-1,xs,ys,line[i].x,line[i].y2);    //初始值就是起点到端点的距离。
  end;
  for i:=be to en do
  begin
    now:=i*2-1; j:=tail[now];
    while j<>0 do
    begin
      if dis[now]+g[j]<dis[l[j]] then
        dis[l[j]]:=dis[now]+g[j];
      j:=next[j];
    end; now:=i*2; j:=tail[now];
    while j<>0 do
    begin
      if dis[now]+g[j]<dis[l[j]] then
        dis[l[j]]:=dis[now]+g[j];
      j:=next[j];
    end;
  end;
  ans:=maxn;
  for i:=be to en do
  begin
    tmp:=dis[i*2-1]+drive(i+1,en,line[i].x,line[i].y1,xt,yt);
    if tmp<ans then ans:=tmp;
    tmp:=dis[i*2]+drive(i+1,en,line[i].x,line[i].y2,xt,yt);
    if tmp<ans then ans:=tmp;
  end; writeln(ans/v:0:10);
end;
//============================================================================
begin
  assign(input,'car.in');
  assign(output,'car.out');
  reset(input); rewrite(output);
  init;
  calculate;
  shortest;
  close(input); close(output);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值