HDU 6097 Mindis(圓的反演)
阿新 • • 發佈:2019-02-15
題意:
有一個圓,圓心是(0,0),半徑是r,有兩個到圓心距離相等的點分佈在圓上或圓內,問在圓上找一點使得這點到那兩個點的距離和,輸出最小的距離。
思路:
首先題目的規模達到了500000,在3s內跑完,如果用三分的話,精度達到1e-6,一個數據大約找50遍,這樣複雜度就爆炸了。
最好的方法是一組資料由一個式子直接得出來,這樣複雜度O(1),還可以跑完。
接下來推公式。
程式碼:
#include <algorithm> #include <string.h> #include <stdio.h> #include <math.h> using namespace std; const double eps=1e-8; typedef pair<double, double>point; double Dist(const point &P1,const point &P2) { double dx=P1.first-P2.first; double dy=P1.second-P2.second; return sqrt(dx*dx+dy*dy); } int main () { point P1,P2; int t; scanf("%d",&t); while(t--) { double R; scanf("%lf",&R); scanf("%lf %lf",&P1.first,&P1.second); scanf("%lf %lf",&P2.first,&P2.second); double C=Dist(P1,P2)/2.0; double D=Dist(point(0,0),P1); if(D<eps) { printf("%.7f\n",R*2.0); continue; } double d=sqrt(D*D-C*C); double a=C*R/D; double y=d*(a*a-C*C)/(C*C); if(y<R-d) { printf("%.7f\n",a*2.0); continue; } printf("%.7f\n",sqrt(C*C+(R-d)*(R-d))*2.0); } return 0; }
附上三分寫的超時的程式碼(以後哪天突然開竅了說不定就不T了):
#include <math.h> #include <stdio.h> #include <iostream> using namespace std; const double eps=1e-7; double r; double xx1,xx2,yy1,yy2; template <class T> inline bool scan_d(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) { return 0; //EOF } while (c != '-' && (c < '0' || c > '9')) { c = getchar(); } sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0' && c <= '9') { ret = ret * 10 + (c - '0'); } ret *= sgn; return 1; } double f1(double x)//關係表示式 { double y=sqrt(r*r-x*x); double ans=sqrt((x-xx1)*(x-xx1)+(y-yy1)*(y-yy1)); double ans2=sqrt((x-xx2)*(x-xx2)+(y-yy2)*(y-yy2)); return ans+ans2; } double sanfen1(double l,double r) { int aa=0; while(r-l>eps) //精度自行設定 {aa++; double ll=(2*l+r)/3; double rr=(l+2*r)/3; double ans1=f1(ll); double ans2=f1(rr); if(ans1>ans2) //符號視情況而定 l=ll; else r=rr; } //cout<<"aa="<<aa<<endl; return f1(l); } double f2(double x)//關係表示式 { double y=-sqrt(r*r-x*x); double ans=sqrt((x-xx1)*(x-xx1)+(y-yy1)*(y-yy1)); double ans2=sqrt((x-xx2)*(x-xx2)+(y-yy2)*(y-yy2)); return ans+ans2; } double sanfen2(double l,double r) { int aa=0; while(r-l>eps) //精度自行設定 {aa++; double ll=(2*l+r)/3; double rr=(l+2*r)/3; double ans1=f2(ll); double ans2=f2(rr); if(ans1>ans2) //符號視情況而定 l=ll; else r=rr; } //cout<<"aa="<<aa<<endl; return f2(l); } int main() { int t; scan_d(t); while(t--) { scan_d(r); scan_d(xx1); scan_d(yy1); scan_d(xx2); scan_d(yy2); double ans=0; if(xx1*xx1+yy1*yy1==r*r) { ans=sqrt((xx2-xx1)*(xx2-xx1)+(yy2-yy1)*(yy2-yy1)); } else if(xx1==-xx2&&yy1==-yy2) ans=2*r; else if(yy1>=0&&yy2>=0) ans=sanfen1(-r,r); else if(yy1<0&&yy2<0) ans=sanfen2(-r,r); else ans=min(sanfen1(-r,r),sanfen2(-r,r)); printf("%.7f\n",ans); } return 0; }