题意 : 给一个圆,两个点,这两个点不在圆外,两个点到圆心距离相等,求圆上点到两个点距离和的最小值。
思路 : 首先要了解反演点
所以极小的 PD + QD 可转化为极小的P'D + Q'D
当P'Q'与圆有交点的时候可以使P'DQ'在同一直线上,这时P'Q'之间的距离就是 ODP' + ODQ'的最小值,那么ODP + ODQ的最小值就等于 P'Q' * (相似的比例)
当P'Q与圆无交点的时候,可以把P' 和 Q'当作一个椭圆的两个交点,我们知道椭圆上的点到椭圆上任意一点的距离之和都相等,所以我们慢慢放大椭圆直到与圆相切的时候,那个点就是最短距离点,你会发现,那个点一定在中垂线上,所以就去求中垂线与圆的交点的距离就可以了
#include
#include
#define eps 1e-8
int main(){
int T;
double r,x1,y1,x2,y2,x3,y3,x4,y4;
double d1,d2,d,k1,k2,dist,ans;
double mx,my,smx,smy;
scanf("%d",&T);
while(T--){
scanf("%lf %lf %lf %lf %lf",&r,&x1,&y1,&x2,&y2);
d1 = sqrt(pow(x1,2) + pow(y1,2)); // 计算出其中一点到圆心距离
k1 = pow(r,2) / pow(d1,2); // 这个 k 由 d(反演点) * d(p点) = r ^ 2 推出
x3 = x1 * k1,y3 = y1 * k1; //用这个比例得出反演点坐标
x4 = x2 * k1,y4 = y2 * k1;
mx = (x3 + x4) / 2; //求出两反演点的中点
my = (y3 + y4) / 2;
d2 = sqrt(pow(mx,2) + pow(my,2)); //中点到圆心的距离可以判断是否与圆相交
if(fabs(d1) <= eps){
ans = 2 * r;
}else if(d2 <= r){
dist = sqrt(pow(x3 - x4,2) + pow(y3 - y4,2));
k2 = d1 / r;
ans = dist * k2;
}else if(d2 > r){
k2 = r / d2;
smx = mx * k2,smy = my * k2;
ans = 2 * (sqrt(pow(smx - x1,2) + pow(smy - y1,2)));
}
printf("%.7f\n",ans);
}
return 0;
}