hud 6097 Mindis(几何)

来源:互联网 发布:怎么能让淘宝店铺靠前 编辑:程序博客网 时间:2024/06/13 09:14

http://acm.hdu.edu.cn/showproblem.php?pid=6097
Problem Description
The center coordinate of the circle C is O, the coordinate of O is (0,0) , and the radius is r.
P and Q are two points not outside the circle, and PO = QO.
You need to find a point D on the circle, which makes PD+QD minimum.
Output minimum distance sum.

Input
The first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with r : the radius of the circle C.
Next two line each line contains two integers x , y denotes the coordinate of P and Q.

Limits
T≤500000
−100≤x,y≤100
1≤r≤100

Output
For each case output one line denotes the answer.
The answer will be checked correct if its absolute or relative error doesn’t exceed 10−6.
Formally, let your answer be a, and the jury’s answer be b. Your answer is considered correct if |a−b|max(1,b)≤10−6.

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

题目大意:给定一个圆心在坐标原点的圆的半径,然后给出两个到该圆的圆心等长的非圆外点P,Q(点既可 以在圆内,也可以在圆上),让从圆上找一点D使其到两点的距离最短,即DP+DQ最小。

解题思路:对于这样的题我们可以分3种情况。
1.P点和Q点重合,这时直接输出2*(R-OP);
2.OP=OQ=R; 这时的最多短距离就是P Q的距离了。
3.OP=OQ < R;这种情况比较麻烦,首先我们要明白一个概念反演点。
反演点:已知圆O的半径为R,从圆心O出发任作一射线,在射线上任取两点M,N。若OM=m,ON=n,且mn=R^2,则称点M,N是关于圆O的反演点。
这里写图片描述
由图可知:
OQ×OQ1 =r×r=|OD|²
易知△ODQ∽△ODQ1 △ODP∽△ODP1
故可以推出OP/OD=DP/DP1 OQ/OD=DQ/DQ1
两式结合DP+DQ=(OP/OD) * DP1+(OQ/OD) * DQ1
又∵OP =OQ
∴DP+DQ=OP/OD(DP1+DQ1)
所以我们只需要求出(DP1+DQ1)的值即可

#include <bits/stdc++.h>using namespace std;double dis(double x1,double y1,double x2,double y2){    double d = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));    return d;}int main(){    int t;scanf("%d",&t);    while(t--)    {        double px,py,qx,qy,r;        scanf("%lf %lf %lf %lf %lf",&r,&px,&py,&qx,&qy);        if(px == qx&&py == qy){///第一种情况            printf("%.7lf\n",2.0*(r - dis(0.0,0.0,px,py)));        }        else if(dis(0.0,0.0,px,py) == r){///第二种情况            printf("%.7lf\n",dis(px,py,qx,qy));        }        else{///第三种情况            double op = dis(px,py,0.0,0.0);            double a = acos((px*qx+py*qy)/(op*op))/2.0 ;///利用反三角函数求出角POD            double op1 = r*r/op;            double od1 = op1*cos(a);///利用角POD求出O点到距离od1            if(od1<=r)            {                printf("%.7lf\n",2.0*op1*sin(a)*(op/r));///若距离小于半径,则最短距离为p1q1*(op/r)            }            else{                double dd1 = od1 - r;                double dp1 = sqrt(dd1*dd1 + (op1*sin(a))*(op1*sin(a)));///否则计算出dp1的距离dq1 = dp1                printf("%.7lf\n",2.0*dp1*op/r);            }        }    }    return 0;}