HDU 6097 Mindis

来源:互联网 发布:洛奇英雄传mac 编辑:程序博客网 时间:2024/06/06 23:59

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

分别对P和Q做关于圆的反演点P1和Q1,以P和P1为例,
OP/OD=OD/OP1=DP/DP1, 所以求出DP1就可以求出DP,同理,DQ也可以这样求出,而所求的DP+ DQ最小值就可以转化为求DP1+DQ1的最小值,其中D为圆上一点,又两点之间直线最短,如果P1Q1与圆有交点,则我们所求的最小DP1+DQ1即为P1Q1此时可以按比例求出DP+ DQ;如果没有,那就中垂线。
比赛时以为一定在中垂线上,然后···GG。
我们不妨设OP1=K*OP,因为OP/OD=OD/OP1=DP/DP1,K=r^2/OP2(r=OD);而P点的坐标我们是知道的,所以P1点是确定的(K*Px,K*Py);同理,Q1点为(K*Qx,K*Qy)(此时K= r^2/OQ2,但OQ和OP是相等的,所以K并不变)。比较原点O到直线P1Q1的距离和圆半径r的大小来判断是哪种情况,分情况输出。
然后我们就可以愉快地敲代码了。
PS:推荐一下大佬的博客,用向量做的。(虽然没看懂)
http://blog.csdn.net/Cai_Haiq/article/details/77093502
AC代码:

#include <bits/stdc++.h>using namespace std;int t;double a,b,r,ans,m,n,k,px,py,qx,qy,ll,l,kl;int main(){    scanf("%d",&t);    while(t--)    {        a=0,b=0;        scanf("%lf",&r);        scanf("%lf %lf",&px,&py);        scanf("%lf %lf",&qx,&qy);        l=sqrt(px*px+py*py);        if(px==qx&&py==qy)        {            ans=(r-l)*2;            printf("%.7lf\n",ans);            continue;        }        else        {            k=r*r/(l*l);            double x3=k*px,y3=k*py,x4=k*qx,y4=k*qy;            double mx= (x3+x4)/2, my = (y3+y4)/2;            ll=sqrt(mx*mx+my*my);            if(ll<=r)            {                //DP=DP1*OP/r, DQ=DQ1*OP/r, DP+DQ=OP/r*(DP1+DQ1)                double dd=sqrt((x3 - x4)*(x3 - x4)+(y3 - y4)*(y3 - y4));//P1Q1的长度                ans=dd * l / r ;            }            else//中垂线,可以直接求圆上的D点,但已经有了相似我们可以根据比例求出            {                kl=r/ll;                m=mx*kl;                n=my*kl;                ans=sqrt((m-px)*(m-px)+(n-py)*((n-py)))*2;            }            printf("%.7lf\n",ans);        }    }    return 0;}