HDU 6097 Mindis 代数方法。
http://acm.hdu.edu.cn/showproblem.php?pid=6097
我们以
PQ
所在直线为
x
轴.垂直PQ 中点直线为
y
轴。建立直角坐标系。
以P,Q 为焦点的椭圆方程为:
x2a2+y2b2=1
其中:
c=|PQ|2b2=a2−c2
如果把
D
看作椭圆上的点。那么就有:
2a=∣∣DP∣∣+∣∣DQ∣∣
令:
d
为O 到
PQ
的距离。
则圆的方程变为:
x2+(y+d)2=R2 , R为圆半径
利用椭圆方程替换圆的方程有:
a2−a2b2y2+(y+d)2−R2=0
得:
−c2b2y2+2yd+d2+a2−R2=0 (1.0)
按照一般思路。当我们增大
a
的时候.
在某一个临界值。此时椭圆刚好与圆第一次有交点。(相切,内切)
但这并不等价于:上面方程(1.0) 有根的前提下。最小的
a
。
因为。
我们在通过圆与椭圆方程合并的过程中丢失了对取值范围的限制条件。
则此时。(1.0) 还需要一个限制。
y∈[0,R−d]
,
这是因为。交点最早出现在
y
的正半轴。
所以。虽然我们a 可能取到了最小值。但同时可能此时
y∉[0,R−d]
对于 (1.0) 的判别式:
Δ=4d2−4−c2b2(d2+a2−R2)≥0
d2+c2(d2+a2−R2)≥0a2≥c2R2d2+c2
对于函数:
f(y)=−c2b2y2+2yd+d2+a2−R2
对称轴为:
−2d2∗−c2b2=db2c2>0
那么当
a
取最小值时。Δ=0
f(y)∣∣y=db2c2=0
如果此时 db2c2∈[0,R−d] : aswer=2a
如果此时 db2c2∉[0,R−d] :
因为
a
此时不能减小。(再小意味着无解。)
对a 增大.
f(y)
的图像会向右偏移的同时上升。
f(y)
的
0
点此时会出现两个。
那么[0,R−d] 最早成为0
点
的值为R−d
将
R−d
带入
f(y)
反解求
a
有:
f(R−d)=0
得:
a2=c2+(R−d)2
搞定。
#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;
}