Analysis
一道计算几何题,难度的话看看它的AC人数就知道了……卡了我好久终于AC了(虽然似乎对联赛没什么帮助T T)。我的做法是先把所有的点按照在多边形上的逆时针方向排序,然后利用叉积求线段之间的交点,并判断点是否在多边形内部。关于叉积求交点的代码我是从《算法艺术与信息学竞赛》上面差不多抄的,然后犯了一个小错误,就是书上的只求规范相交,要改一改才行……
Accepted Code
type
point=record
x,y:extended;
end;
var
n,m,i,j,cnt,t:longint;
p,ans:array[0..500] of point;
q1,q2,poi:point;
bo1,bo2,online:boolean;
function cross(a,b,c:point):extended;
begin
cross:=(b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
end;
function samepoint(a,b:point):boolean;
begin
samepoint:=(abs(a.x-b.x)<1e-6) and (abs(a.y-b.y)<1e-6);
end;
function dblcmp(t:extended):longint;
begin
if abs(t)<1e-6 then
dblcmp:=0
else
if t>0 then
dblcmp:=1
else
dblcmp:=-1;
end;
function between(c,a,b:point):boolean;
begin
if a.x<b.x then
between:=(a.x<=c.x) and (c.x<=b.x)
else
if a.x>b.x then
between:=(b.x<=c.x) and (c.x<=a.x)
else
if a.y<b.y then
between:=(a.y<=c.y) and (c.y<=b.y)
else
between:=(b.y<=c.y) and (c.y<=a.y);
end;
function segcross(a,b,c,d:point):longint;
var
d1,d2,d3,d4:longint;
s1,s2,s3,s4:extended;
begin
s1:=cross(a,b,c);
s2:=cross(a,b,d);
s3:=cross(c,d,a);
s4:=cross(c,d,b);
d1:=dblcmp(s1);
d2:=dblcmp(s2);
d3:=dblcmp(s3);
d4:=dblcmp(s4);
if (d1<>d2) and (d3<>d4) then
begin
poi.x:=(c.x*s2-d.x*s1)/(s2-s1);
poi.y:=(c.y*s2-d.y*s1)/(s2-s1);
segcross:=1;
exit;
end;
if ((d1=0) and between(c,a,b)) or ((d2=0) and between(d,a,b)) or ((d3=0) and between(a,c,d)) or ((d4=0) and between(b,c,d)) then
segcross:=2
else
segcross:=0;
end;
begin
readln(n);
for i:=1 to n do
readln(p[i].x,p[i].y);
for i:=2 to n do
if (p[i].x<p[1].x) or ((p[i].x=p[1].x) and (p[i].y<p[1].y)) then
begin
p[0]:=p[1];
p[1]:=p[i];
p[i]:=p[0];
end;
for i:=2 to n-1 do
for j:=i+1 to n do
if ((p[i].y-p[1].y)*(p[j].x-p[1].x)>(p[j].y-p[1].y)*(p[i].x-p[1].x)) or (p[i].x=p[1].x) then
begin
p[0]:=p[i];
p[i]:=p[j];
p[j]:=p[0];
end;
readln(m);
while m>0 do
begin
dec(m);
readln(q1.x,q1.y,q2.x,q2.y);
bo1:=true;
bo2:=true;
online:=false;
cnt:=0;
for i:=1 to n-1 do
begin
bo1:=bo1 and (cross(p[i],p[i+1],q1)>0);
bo2:=bo2 and (cross(p[i],p[i+1],q2)>0);
t:=segcross(q1,q2,p[i],p[i+1]);
if t=1 then
begin
inc(cnt);
ans[cnt]:=poi;
end
else
if t=2 then
begin
online:=true;
break;
end;
end;
if not online then
begin
bo1:=bo1 and (cross(p[n],p[1],q1)>0);
bo2:=bo2 and (cross(p[n],p[1],q2)>0);
t:=segcross(q1,q2,p[n],p[1]);
if t=1 then
begin
inc(cnt);
ans[cnt]:=poi;
end
else
if t=2 then
online:=true;
end;
for i:=1 to cnt-1 do
for j:=i+1 to cnt do
if (ans[j].x<ans[i].x) or ((ans[j].x=ans[i].x) and (ans[j].y<ans[i].y)) then
begin
ans[0]:=ans[i];
ans[i]:=ans[j];
ans[j]:=ans[0];
end;
i:=cnt;
while i>=2 do
begin
if samepoint(ans[i],ans[i-1]) then
begin
ans[0]:=ans[i];
ans[i]:=ans[cnt];
ans[cnt]:=ans[0];
dec(cnt);
end;
dec(i);
end;
if online then
writeln(0)
else
if bo1 and bo2 then
writeln((sqrt(sqr(q1.x-q2.x)+sqr(q1.y-q2.y))):0:2)
else
if bo1 or bo2 then
if bo1 then
writeln(sqrt(sqr(q1.x-ans[1].x)+sqr(q1.y-ans[1].y)):0:2)
else
writeln(sqrt(sqr(q2.x-ans[1].x)+sqr(q2.y-ans[1].y)):0:2)
else
if cnt=2 then
writeln(sqrt(sqr(ans[1].x-ans[2].x)+sqr(ans[1].y-ans[2].y)):0:2)
else
writeln(0);
end;
end.