1. 程式人生 > >hdu 6097 Mindis(圓上一點到圓內(距圓心相等的)兩點的距離和最短)

hdu 6097 Mindis(圓上一點到圓內(距圓心相等的)兩點的距離和最短)

Mindis

題意:圓內或者圓周上有兩個點pq,圓心為o,並且op=oq,讓你在圓上找一點d,使得dp+dq最小

官方題解:
這裡寫圖片描述

為什麼是中垂線上的點取得最小值?
個人理解應該是類似於這種情況吧,不過任誰做這道題時首先想到的應該都是中垂線吧。。
這裡寫圖片描述

還有就是極端情況,做出反演點(什麼是反演點

如果直線pq與圓有交點,則答案為兩點間距離
否則答案就在中垂線上取到

看著題解寫程式碼很簡單,問題就是這些結論怎麼證的(蒻蒻記住結論,求路過的大佬解惑)。。。

程式碼:

#include<bits/stdc++.h>
using namespace std;

const
double eps=1e-8; struct point//點 { double x,y; point() {} point(double X,double Y) { x=X,y=Y; } }; double xmult(point p1,point p2,point p0)//叉積 { return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); } double dis(point p1,point p2)//兩點間距離 { return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); } double
disptoline(point p,point l1,point l2)//點到直線的距離 { return fabs(xmult(p,l1,l2))/dis(l1,l2); } int intersect_line_circle(point c,double r,point l1,point l2)//判定直線是否與圓相交 { return disptoline(c,l1,l2)<r+eps; } int main() { int T_T; double r,ans; point p,q,o(0,0); scanf("%d",&T_T); while
(T_T--) { scanf("%lf%lf%lf%lf%lf",&r,&p.x,&p.y,&q.x,&q.y); double op=dis(p,o); if(p.x==q.x&&p.y==q.y)//特判兩點在同一位置 ans=2.0*(r-op); else { point p1(r*r/op/op*p.x,r*r/op/op*p.y),q1(r*r/op/op*q.x,r*r/op/op*q.y);//p'和q' if(intersect_line_circle(o,r,p1,q1))//判定直線是否與圓相交 ans=dis(p1,q1)*op/r; else { point mid((q1.x+p1.x)/2,(q1.y+p1.y)/2);//兩個反演點的中點 double k=r/dis(mid,o);//比例 point d(k*mid.x,k*mid.y);//得到中垂線上的點 ans=2*dis(d,q);//兩點到中垂線的距離相等所以×2 } } printf("%.7lf\n",ans); } return 0; }

ps:解釋一下程式碼中的ans=dis(p1,q1)*op/r
反演點有一個定理:

                           dpdp=opop   (d為圓上任意一點)

opop=r2

dp=dpop2r2=dpopr
同理可得dq=dqop2r2=dqoqr
op=oq,因此ans=dis(p1,q1)*op/r