2017 Multi-University Training Contest

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6097

分析:考虑P关于圆O的反演点P',对于圆上任意一点M,|PM|/|P'M|=|OP|/r,然后就把问题转化为圆外两点到圆上动点距离之和最小了,因为|OP|=|OQ|,线段P'Q'要么和圆有交点,要么所在直线与圆都没有交点,前一种情况,显然|P'M|+|Q'M|>=|P'Q'|,等号当M在P'Q'上时取得,后一种情况,作与P'Q'平行的切线,切点就是M,由于|OP|=|OQ|,M也就是PQ中垂线与圆的交点,勾股定理一下就行了。P'   Q'并不需要求出来,利用相似,算△OPQ就可以了,再乘个比例。最后还要注意PQ重合的情况。。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 using namespace std;
 6 int xx1,yy1,xx2,yy2,r;
 7 inline double ABS(double x){
 8     if(x<0)return -x;
 9     return x;
10 }
11 double dis(int x1,int y1,int x2,int y2){
12     return sqrt(1.0*((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)));
13 }
14 double solve(){
15     if(xx1==xx2&&yy1==yy2){
16         return 2.0*r-2.0*dis(xx1,yy1,0,0);
17     }
18     double op=dis(xx1,yy1,0,0),pq=dis(xx1,yy1,xx2,yy2),d;
19     if(xx1==xx2)
20         d=(xx1>=0?xx1:-xx1);
21     else if(yy1==yy2)
22         d=(yy1>=0)?yy1:-yy1;
23     else
24         d=ABS(xx1*yy2-yy1*xx2)/dis(xx1,yy1,xx2,yy2);
25     d=d*r*r/(op*op);
26     if(d<=r){
27         double q=2*sqrt(r*r+op*op-2.0*r*sqrt(op*op-(pq*pq)/4));
28         return r*pq/op;
29     }else{
30         return 2*sqrt(r*r+op*op-2.0*r*sqrt(op*op-(pq*pq)/4));
31     }
32 }
33 int main(){
34     //freopen("e:\in.txt","r",stdin);
35     int t;
36     scanf("%d",&t);
37     while(t--){
38         scanf("%d%d%d%d%d",&r,&xx1,&yy1,&xx2,&yy2);
39         printf("%.8f
",solve());
40     }
41     return 0;
42 }
原文地址:https://www.cnblogs.com/7391-KID/p/7341928.html