HDU 6097 Mindis(计算几何)

来源:互联网 发布:签章软件下载 编辑:程序博客网 时间:2024/06/06 10:07

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|=r2r|OP|=|OP|r,即OPD~ODP,同理对于Q点关于圆心的反演点QOQD~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<cstdio>#include<cmath>using namespace std;#define eps 1e-8int sign(double x){    if(fabs(x)<eps)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;}
原创粉丝点击