hdu 6097 Mindis (反演点)

来源:互联网 发布:淘宝 串货 编辑:程序博客网 时间:2024/06/05 02:25

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

题目大意:给你圆内两个点P、Q,求圆上一点D,使得 |QD|+|PD|最短

在此之前我们先了解一下反演点的知识,参照百度百科:

一般指二维反演中的点。
二维上反演以一个特定的反演圆为基础:圆心O为反演中心,圆半径为常数k,把点P反演为点P'就是使得OP×OP'=r^2.
如点P在圆外可这样作:过点P作圆的切线(两条),两个切点相连与OP连线交点就是点P'.
如点P在圆内就把这一过程反过来即可:连结OP,过点P作直线垂直于OP,直线与圆的交点处的切线的交点就是点P'.
如点P在圆上,反演后仍是它自身.按上述方法都可用尺规作图完成.

题目思路:

那么可以知道因为OP*OP'=r*r

那么易证明对于圆上任意一点T,▲OP'T与▲OTP相似 (因为两对边比例相等且夹角相等都为∠POT)

知道这个结论之后,我们求的 min|QD|+|PD| 可以转化为求 min|Q'D|+|P'D| 然后再按边的比例即可得到解

如果直线P'Q'与圆没有交点,那么答案为PQ中垂线与圆的交点。

否则答案为|P'Q'|

#include<bits/stdc++.h>using namespace std;const double eps=1e-8;struct point{double x,y;};double distance1(point p1,point p2)//求两点的距离 {return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}point intersection(point u1,point u2,point v1,point v2)//求两条直线交点 {point ret=u1;double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));ret.x+=(u2.x-u1.x)*t;ret.y+=(u2.y-u1.y)*t;return ret;}void intersection_line_circle(point c,double r,point l1,point l2,point& p1,point& p2)//求直线与圆交点 {point p=c;double t;p.x+=l1.y-l2.y;p.y+=l2.x-l1.x;p=intersection(p,c,l1,l2);double temp=r*r-distance1(p,c)*distance1(p,c);t=sqrt(temp)/distance1(l1,l2);p1.x=p.x+(l2.x-l1.x)*t;p1.y=p.y+(l2.y-l1.y)*t;p2.x=p.x-(l2.x-l1.x)*t;p2.y=p.y-(l2.y-l1.y)*t;}double ptoline(point p,point l1,point l2) { point midp; midp.x=(l1.x+l2.x)/2.0;midp.y=(l1.y+l2.y)/2.0;return distance1(p,midp);}point invpoint(point p,double k)//求点p对于原点O的反演点 {//反演点为向量x伸长 k倍point invp;invp.x=p.x*k;invp.y=p.y*k;return invp;}double solve(){double r,ans;point O,P,Q,invP,invQ,PQmid;scanf("%lf",&r);scanf("%lf%lf%lf%lf",&P.x,&P.y,&Q.x,&Q.y);O.x=O.y=0;//原点O为圆心 PQmid.x=(P.x+Q.x)/2.0;PQmid.y=(P.y+Q.y)/2.0;double k=(r*r/distance1(P,O)/distance1(P,O));invP=invpoint(P,k);invQ=invpoint(Q,k);if(distance1(P,O)<eps) ans=2.0*r;else if(r<ptoline(O,invP,invQ)) //两个反演点的连线在圆外,则答案为垂直平分线与圆的交点{point p1,p2;intersection_line_circle(O,r,O,PQmid,p1,p2);//求直线与圆交点 ans=min(distance1(P,p1)+distance1(Q,p1),distance1(P,p2)+distance1(Q,p2));} else {//cout<<"反演点"<<endl;ans=distance1(invP,invQ);ans*=distance1(P,O)/r;}return ans;}int main(){int T;scanf("%d",&T);while(T--) printf("%.8lf\n",solve());}




原创粉丝点击