[SGU]129. Inheritance

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.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值