hdu 6097 Mindis(數學幾何,圓心的反演點)
Mindis
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2787 Accepted Submission(s): 555
Special Judge
P and Q are two points not outside the circle, and PO = QO.
You need to find a point D on the circle, which makes PD+QD
Output minimum distance sum.
Input The first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with r : the radius of the circle C.
Next two line each line contains two integers x , y denotes the coordinate of P and Q.
Limits
T≤500000
?100≤x,y≤100
1≤r≤100
Output For each case output one line denotes the answer.
The answer will be checked correct if its absolute or relative error doesn‘t exceed 10?6.
Formally, let your answer be a, and the jury‘s answer be b. Your answer is considered correct if |a?b|max(1,b)≤10?6. Sample Input 4 4 4 0 0 4 4 0 3 3 0 4 0 2 2 0 4 0 1 1 0 Sample Output
題意:
圓心 O 坐標(0, 0), 給定兩點 P, Q(不在圓外),滿足 PO = QO,
要在圓上找一點 D,使得 PD + QD 取到最小值。
官方題解:
做P點關於圓的反演點P‘,OPD與ODP‘相似,相似比是|OP| : r。
Q點同理。
極小化PD+QD可以轉化為極小化P‘D+Q‘D。
當P‘Q‘與圓有交點時,答案為兩點距離,否則最優值在中垂線上取到。
時間復雜度 O(1)O(1)
補充說明:
反演:
設在平面內給定一點O和常數k(k不等於零),對於平面內任意一點A,確定A′,使A′在直線OA上一點,並且有向線段OA與OA′滿足OA·OA′=k,我們稱這種變換是以O為的反演中心,以k為反演冪的反演變換,簡稱反演。——百度百科
在這裏,k 即為圓半徑 r ^ 2,因此,相似就是顯然的了。
當 P‘Q‘ 與圓有交點時:
不妨設交點為 O‘,若 D 不為 O‘,則 P‘D + Q‘D > P‘Q‘(三角形兩邊之和大於第三邊);當且僅當 D 取 O‘ 時,P‘Q + Q‘D 取到最小值,即為 P‘Q‘。
當 P‘Q‘ 與圓無交點時:
不妨將 P‘ 與 Q‘ 看成橢圓的兩個焦點,當橢圓慢慢變大時,第一個碰到的圓上的點 D 即為使得 P‘D + Q‘D 最小的點;畫個圖就很顯然了,第一個碰到的點即為 PQ 的中垂線與圓的交點。
至於判斷有 P‘Q‘ 與圓有沒有交點,就是圓心到直線的距離與半徑比較,又因為此處 P‘O=Q‘O,所以只需要比較 P‘Q‘ 的中點到圓心的距離和半徑的大小。
註意點:
1. 註意 PO = QO = 0 的情況
2. 盡量用比例而不是角度進行計算
這題精度很是問題#include <iostream> #include<bits/stdc++.h> using namespace std; const double eps=1e-8; int t; double R,px,py,qx,qy; int main() { scanf("%d",&t); while(t--) { scanf("%lf%lf%lf%lf%lf",&R,&px,&py,&qx,&qy); if (px==0 && py==0) {printf("%.7lf\n",2*R);continue;} double r=sqrt(pow(px,2)+pow(py,2)); double k=R*R/(r*r); //不是相似比 double ppx=px*k,ppy=py*k,qqx=qx*k,qqy=qy*k; //printf("%.2lf %.2lf\n",ppx,ppy); double midx=(ppx+qqx)/2,midy=(ppy+qqy)/2; double dis=sqrt(pow(midx,2)+pow(midy,2) ); //printf("%.7lf\n",dis); if (dis<=R) { // double op2=sqrt(pow(ppx,2)+pow(ppy,2)); printf("%.7lf\n",sqrt(pow(ppx-qqx,2)+pow(ppy-qqy,2))*r/R); } else { double mx=midx/dis*R; double my=midy/dis*R; printf("%.7lf\n",2*sqrt(pow(mx-px,2)+pow(my-py,2)) ); } } return 0; }
hdu 6097 Mindis(數學幾何,圓心的反演點)