题意:
有一个圆,圆心是(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;
}