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.