题解:洛谷 AT_abc460_b Two Rings
【题目来源】
洛谷:AT_abc460_b [ABC460B] Two Rings - 洛谷
【题目描述】
在平面直角坐标系 \(xy\) 中有两个圆 \(C_1\) 和 \(C_2\),在此题中,圆指的是圆周。
圆 \(C_1\) 的圆心在点 \((X_1,Y_1)\) 上,其半径为 \(R_1\)。
圆 \(C_2\) 的圆心在点 \((X_2,Y_2)\) 上,其半径为 \(R_2\)。
你需要判断这两个圆是否相交。换句话说,你需要判断是否有至少一个点,它到 \((X_1,Y_1)\) 的距离为 \(R_1\),到 \((X_2,Y_2)\) 的距离为 \(R_2\)。
给定 \(T\) 个测试用例,你需要分别求出答案。
【输入】
输入以如下格式给出,其中 \(\operatorname{case}_i\) 为第 \(i\) 个测试用例。
\(T\)
\(\operatorname{case_1}\)
\(\operatorname{case_2}\)
\(...\)
\(\operatorname{case_T}\)
各测试用例以如下格式给出。
\(X_1\) \(Y_1\) \(R_1\) \(X_2\) \(Y_2\) \(R_2\)
【输出】
输出 \(T\) 行,第 \(i\) 行表示第 \(i\) 个测试用例的答案。
在每个测试用例中,如果 \(C_1\) 和 \(C_2\) 相交则输出 Yes,否则输出 No。
【输入样例】
7
0 0 2 2 3 2
0 0 2 2 3 1
1 2 5 3 2 1
5 4 2 8 8 3
2 1 5 5 1 2
0 0 1 0 0 1
0 0 500000000 1 1000000000 500000000
【输出样例】
Yes
No
No
Yes
Yes
Yes
No
【核心思想】
-
问题分析:给定 \(T\) 组测试用例,每组包含两个圆的圆心坐标和半径,判断两圆是否相交(即圆周上是否存在公共点)。这是一个几何判定问题,核心在于利用圆心距与半径和/差的关系进行精确判断,同时避免浮点精度问题。
-
算法选择:
- 距离平方比较:计算圆心距的平方 \(d^2 = (X_1 - X_2)^2 + (Y_1 - Y_2)^2\),与半径和的平方 \((R_1 + R_2)^2\) 和半径差的平方 \((R_1 - R_2)^2\) 比较
-
关键步骤:
- 读入数据:\(T\),以及 \(T\) 组 \((X_1, Y_1, R_1, X_2, Y_2, R_2)\)
- 计算圆心距平方:\(d \leftarrow (X_1 - X_2)^2 + (Y_1 - Y_2)^2\)
- 计算半径和与差的平方:\(rSum \leftarrow R_1 + R_2\),\(rSub \leftarrow R_1 - R_2\)
- 相交判定:
- 若 \((R_1 - R_2)^2 \leq d \leq (R_1 + R_2)^2\):输出
Yes - 否则:输出
No
- 若 \((R_1 - R_2)^2 \leq d \leq (R_1 + R_2)^2\):输出
- 注意:\(d\) 是圆心距的平方,因此与半径和/差的平方直接比较
-
时间/空间复杂度:
- 时间复杂度:\(O(T)\),每组测试用例 \(O(1)\) 计算
- 空间复杂度:\(O(1)\)
-
几何判定与整数运算的核心思想:
- 相交的充要条件:两圆相交(有公共点)\(\Leftrightarrow |R_1 - R_2| \leq \text{圆心距} \leq R_1 + R_2\)。左边保证一圆不完全包含另一圆(内含不相交),右边保证两圆不分离
- 平方避免开方:不计算圆心距 \(\sqrt{d}\),而是将不等式两边平方,得到 \((R_1 - R_2)^2 \leq d \leq (R_1 + R_2)^2\),完全避免浮点运算和精度损失
- 半径差的处理:\(R_1 - R_2\) 可能为负,但平方后 \((R_1 - R_2)^2 = (R_2 - R_1)^2\),因此无需取绝对值
- 大数安全:坐标和半径可达 \(10^9\),圆心距平方可达 \((2 \times 10^9)^2 = 4 \times 10^{18}\),需要使用
long long(#define int long long)防止溢出 - 适用于基础几何判定、浮点精度规避类问题
【算法标签】
入门 #数学
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
int t; // 测试用例数量
signed main()
{
cin >> t; // 输入测试用例数量
while (t--) // 处理每个测试用例
{
int x1, y1, r1, x2, y2, r2; // 两个圆的圆心坐标和半径
cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2; // 输入两个圆的参数
int dx = x1 - x2; // 圆心横坐标差
int dy = y1 - y2; // 圆心纵坐标差
int d = dx * dx + dy * dy; // 圆心距离的平方
int rSum = r1 + r2; // 半径和
int rSub = r1 - r2; // 半径差
if (d <= rSum * rSum && d >= rSub * rSub) // 判断两圆是否相交
cout << "Yes" << endl; // 相交
else
cout << "No" << endl; // 不相交
}
return 0;
}
【运行结果】
7
0 0 2 2 3 2
Yes
0 0 2 2 3 1
No
1 2 5 3 2 1
No
5 4 2 8 8 3
Yes
2 1 5 5 1 2
Yes
0 0 1 0 0 1
Yes
0 0 500000000 1 1000000000 500000000
No
浙公网安备 33010602011771号