题解:洛谷 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

【核心思想】

  1. 问题分析:给定 \(T\) 组测试用例,每组包含两个圆的圆心坐标和半径,判断两圆是否相交(即圆周上是否存在公共点)。这是一个几何判定问题,核心在于利用圆心距与半径和/差的关系进行精确判断,同时避免浮点精度问题。

  2. 算法选择

    • 距离平方比较:计算圆心距的平方 \(d^2 = (X_1 - X_2)^2 + (Y_1 - Y_2)^2\),与半径和的平方 \((R_1 + R_2)^2\) 和半径差的平方 \((R_1 - R_2)^2\) 比较
  3. 关键步骤

    • 读入数据\(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
    • 注意:\(d\) 是圆心距的平方,因此与半径和/差的平方直接比较
  4. 时间/空间复杂度

    • 时间复杂度:\(O(T)\),每组测试用例 \(O(1)\) 计算
    • 空间复杂度:\(O(1)\)
  5. 几何判定与整数运算的核心思想

    • 相交的充要条件:两圆相交(有公共点)\(\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
posted @ 2026-08-26 10:12  团爸讲算法  阅读(5)  评论(0)    收藏  举报