The 2019 ACM-ICPC China Shannxi Provincial Programming Contest C.Angel's Journey(计算几何基础)

    xiaoxiao2025-08-31  4

    题目

    T(T<=500)组样例,每组样例给出rx,ry,r,x,y(-100<=rx,ry,x,y<=100,0<r<=100)

    代表被救的人在(rx,ry-r)位置,且(rx,ry)为圆心有一个半径为r的圆

    你从圆外(x,y)出发,题目保证y>ry,

    y=ry及这条水平线以下的圆外部分是海,圆内部也是海,都不能经过

    问(x,y)到(rx,ry-r)的最短距离

    思路来源

    归神代码

    题解

    记A(x,y),O(rx,ry),S(rx,ry-r),D(rx+r,ry),E(rx-r,ry)

    过A的直线与圆的切点F,坐标未知

    考虑棕色边的三角形AOS,余弦定理求顶角AOS,

    余弦定理求直角三角形AFO的角AOF,作差得角FOS

    ①角FOS小于90度,说明FOS在海里,不可通过直线达,取点E和点D的较近点,再走1/4弧

    ②角FOS大于90度,FOS可以通过与切点的线段到达,再走圆上一段弧即可

    这种判断,省去了对两个切点的分别判断,感觉比较巧妙吖

    代码

    #include<bits/stdc++.h> #define db double using namespace std; const db pi=acos(-1.0); const db eps=1e-8; db dis2(db x,db y,db i,db j) { return (x-i)*(x-i)+(y-j)*(y-j); } int t; db rx,ry,r,x,y,ex,ey; db a,b,arg1,arg2,arg3; db res; int main() { scanf("%d",&t); while(t--) { scanf("%lf%lf%lf%lf%lf",&rx,&ry,&r,&x,&y); ex=rx;ey=ry-r; a=dis2(x,y,rx,ry); b=dis2(x,y,ex,ey); arg1=acos((a+r*r-b)/(2.0*sqrt(a)*r)); arg2=acos(r/sqrt(a)); arg3=arg1-arg2; if(arg3<=pi/2+eps)//切点在下半圆周 { if(x<rx)res=dis2(x,y,rx-r,ry); else res=dis2(x,y,rx+r,ry); printf("%.4lf\n",sqrt(res)+pi*r/2.0); } else printf("%.4lf\n",sqrt(a-r*r)+arg3*r); } return 0; }

     

    最新回复(0)