高中数学学得贼烂,怎么说呢,如果高三做也许会做,现在就有点要GG的感觉
反演点:二维上反演以一个特定的反演圆为基础:圆心O为反演中心,圆半径为常数k,把点P反演为点P'就是使得OP×OP'=r^2.
题意:
圆心 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)
为什么要选择反演点呢,因为如果选择相似三角形已知的比例只有r/d,刚好符合反演点,只能说反演点在同心圆中被用到的多了,有了这么一个名字,如果没有这个反演点的名字也要这么搞,因为已知的条件,只有角相等,r和d的长度。。。。
#include <bits/stdc++.h>
#define eps 1e-8
void work() {
double r, x1, y1, x2, y2;
scanf("%lf%lf%lf%lf%lf", &r, &x1, &y1, &x2, &y2);
double d0 = sqrt(pow(x1, 2) + pow(y1, 2));
if (fabs(d0) < eps) {
printf("%.7f\n", 2 * r);
return;
}
double k = r * r / (d0 * d0);
double x3 = x1 * k, x4 = x2 * k, y3 = y1 * k, y4 = y2 * k;
double mx = (x3+x4)/2, my = (y3+y4)/2, ans;
double d = sqrt(pow(mx,2)+pow(my,2));
if (d <= r) {
double dist = sqrt(pow(x3 - x4, 2) + pow(y3 - y4, 2));
ans = dist * d0 / r;
}
else {
double kk = r / d;
double smx = mx * kk, smy = my * kk;
ans = 2 *sqrt(pow(smx - x1, 2) + pow(smy - y1, 2));
}
printf("%.7f\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}