HDU 6097 Mindis(计算几何)

Description

给出一个圆心为 O(0,0) ,半径为 r 的圆,并给出圆内两个距圆心等距的点 P,Q ,要求在圆上找一个点 D ,使得 |PD|+|QD| 最小,输出最小值

Input

第一行一个整数 T 表示用例组数,每组用例首先输入一整数 r 表示圆的半径,之后输入 P,Q 两点的横纵坐标 xp,yp,xq,yq ,保证 |OP|=|OQ| (T500000,100xp,yp,xq,yq100,1r100)

Output

对于每组用例,输出 |PD|+|QD| 的最小值,结果和精确值的相对误差及绝对误差不超过 106

Sample Input

4
4
4 0
0 4
4
0 3
3 0
4
0 2
2 0
4
0 1
1 0

Sample Output

5.6568543
5.6568543
5.8945030
6.7359174

Solution

考虑 P 点关于圆心的反演点 P ,由 |OP||OP|=r2 r|OP|=|OP|r ,即 OPD ~ ODP ,同理对于 Q 点关于圆心的反演点 Q OQD ~ ODQ ,相似比为 |OP|r ,且有 OPQ ~ OPQ ,相似比为 |PQ||PQ|=|OP|2r2

如果 |OP|=0 ,说明 P,Q,O 重合,显然答案是 2r

如果 |OP|>0 ,由于 |PD|+|QD|=r|OP|(|PD|+|QD|) ,若 PQ 与圆相交则显然右端最小值为 r|OP||PQ|=|OP|r|PQ| ,如果不相交则 D 点取线段 PQ 的中垂线和圆的交点时 |PD|+|QD| 最小,此时通过求出线段 PQ 中点 R 的坐标及 |OD||OR|=r|OR 可以得到 D 点坐标

Code

#include
#include
using namespace std;
#define eps 1e-8
int sign(double x)
{
    if(fabs(x)return 0;
    if(x>eps)return 1;
    return -1;
}
double dis(double x0,double y0,double x1,double y1)
{
    double x=x1-x0,y=y1-y0;
    return sqrt(x*x+y*y);
}
int main()
{
    int T;
    double xp,yp,xq,yq,r;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lf%lf%lf%lf%lf",&r,&xp,&yp,&xq,&yq);
        double OP=dis(xp,yp,0,0),ans;
        if(sign(OP)==0)ans=2.0*r;
        else
        {
            double xr=0.5*(xp+xq),yr=0.5*(yp+yq);
            double OR=dis(xr,yr,0,0);
            double ORR=OR*r*r/(OP*OP);
            if(sign(ORR-r)<=0)ans=dis(xp,yp,xq,yq)*r/OP;
            else
            {
                double xs=xr*r/OR,ys=yr*r/OR;
                ans=2.0*dis(xp,yp,xs,ys);
            }
        }
        printf("%.10f\n",ans+eps);
    }
    return 0;
}

你可能感兴趣的:(HDU,计算几何)