Hit! Gym - 101522H (2)“三角形相似”
题意:
分别给出两个圆的圆心坐标和半径长度,并保证两个圆有公共部分(相交/相切/内含),输出一个位于公共部分的点的坐标,答案不唯一。
注意一下距离的精度10^-5。
做法:
下面以一个简单的例子说明,其他可以类比。
我们假设两个圆的半径分别为r1, r2, 两圆相交部分的长度为x。标注A, B, C, D四个点,分别过B, C, D点作垂线。图如下:
把图简化一下,只留下最重要的部分:
我们的代码是这样的,通过两个圆的半径长度的比值,然后直接得到一个,在连接两圆圆心的线段上的点,并且这个点就是两个圆相交部分中的一个点。
k = r1 / (r1 + r2);
x = x1 + k * (x2 - x1);
y = y1 + k * (y2 - y1);
可是为什么呢?这个点为什么会在两个圆的相交部分呢?
我们已经假设两圆相交部分的长度为x,AC = r1, BD = r2, 则AB = r1-x, AD = r1+r2-x。
由此,我们可以得到一个式子,它解释了为什么。
(r1-x)/(r1+r2-x) <= r1/(r1+r2) <= r1/(r1+r2-x)
中间部分的r1/(r1+r2),就是我们代码中的k。首先,我么可以通过通分,检验一下式子的正确性。
把前面设的变量代入,上式也可以表示为:
AB/AD <= AC/(r1+r2) <= AC/AD
B, C是x的两个端点,这个比例式说明,在BC即x的长度内确实存在一个点,满足条件。结合两个公式和图,认真多看几遍,拿笔比划比划,就会明白了。
#include <stdio.h>
int
main() {
double x1, x2, y1, y2, r1, r2;
double k, x, y;
scanf("%lf %lf %lf", &x1, &y1, &r1);
scanf("%lf %lf %lf", &x2, &y2, &r2);
k = r1 / (r1 + r2);
x = x1 + k * (x2 - x1);
y = y1 + k * (y2 - y1);
printf("%f %f\n", x, y);
return 0;
}