PAT乙级1082题解:欧几里得距离算法与应用
2026/9/17 11:47:27 网站建设 项目流程

1. 题目解析与解题思路

这道PAT乙级1082题目看似简单,但蕴含着几个值得深入探讨的算法思维点。题目要求我们处理一组包含ID和二维坐标的数据,找出距离原点最近和最远的两个点对应的ID。这在实际应用中很常见,比如寻找最近的配送点或最远的监测站。

核心算法逻辑非常清晰:对于每个输入的点,计算其到原点的欧几里得距离(这里用距离平方代替实际距离以避免浮点数运算),然后维护两个变量分别记录当前的最小和最大距离及其对应的ID。

注意:题目中使用的是整数坐标,且输出要求ID用4位数字表示(不足补零),这是PAT题目常见的格式要求,需要特别注意。

2. 代码实现详解

让我们逐行分析给出的C++解决方案:

#include<bits/stdc++.h> using namespace std; int main() { int n; cin >> n; // 读取点的数量 int id,x,y; // 临时变量存储每个点的信息 int guan = 0,cai = 0; // 存储最近和最远点的ID int maxdis = -1,mindis = 999999; // 初始化的极值 for(int i = 0; i < n; i ++) { cin >> id >> x >> y; // 计算距离平方 int distance = x*x + y*y; // 更新最大距离记录 if(distance > maxdis) { cai = id; maxdis = distance; } // 更新最小距离记录 if(distance < mindis) { guan = id; mindis = distance; } } // 格式化输出,保证4位数字 printf("%04d %04d", guan, cai); return 0; }

2.1 关键变量说明

  1. n:表示要处理的点的数量
  2. id, x, y:临时存储每个点的ID和坐标
  3. guancai:分别记录最近和最远点的ID
  4. maxdismindis:记录当前的最大和最小距离平方值

2.2 算法优化点

  1. 距离计算优化:直接使用距离平方而非实际距离,避免了耗时的平方根运算,同时不影响比较结果。
  2. 初始化技巧maxdis初始化为-1,mindis初始化为一个大数,确保第一个点能正确更新这两个值。
  3. 输入输出处理:使用printf的格式化输出确保ID显示为4位数字,这是PAT题目常见的要求。

3. 常见问题与调试技巧

在实际编码和调试过程中,可能会遇到以下问题:

3.1 边界条件处理

  1. n=0的情况:虽然题目可能保证n>0,但健壮的代码应该考虑这种边界情况。
  2. 坐标全为0:所有点都在原点时,最大和最小距离相同,代码仍能正确处理。
  3. 多个点有相同距离:题目没有说明如何处理这种情况,按照当前代码会保留最先出现的点。

3.2 调试技巧

  1. 打印中间变量:在循环中加入cout << "当前距离:" << distance << endl;可以帮助验证计算是否正确。
  2. 测试用例设计
    • 单点情况
    • 所有点在x轴上的情况
    • 对称分布的点
    • 包含(0,0)点的情况

提示:在PAT系统中,经常会有一些边界测试用例,因此编写代码时要特别注意边界条件的处理。

4. 算法复杂度分析

让我们分析这个解决方案的时间和空间复杂度:

  1. 时间复杂度:O(n)

    • 只需要一次遍历所有点
    • 每个点的处理时间是常数时间(计算距离和比较)
  2. 空间复杂度:O(1)

    • 只使用了固定数量的变量
    • 不需要存储所有点的信息

这是这个问题的最优解法,无法在复杂度上进一步优化。

5. 代码风格与改进建议

虽然这个解决方案功能正确,但从工程角度还可以做一些改进:

  1. 变量命名guancai这样的命名不够直观,可以改为min_idmax_id
  2. 常量定义999999这样的魔数应该定义为常量,如const int INF = 1e6
  3. 输入验证:可以添加对n的范围检查
  4. 注释:关键逻辑应该添加注释说明

改进后的代码可能如下:

#include<bits/stdc++.h> using namespace std; const int INF = 1e6; int main() { int n; cin >> n; if(n <= 0) return 0; // 处理无效输入 int id, x, y; int min_id = 0, max_id = 0; int max_dist = -1, min_dist = INF; for(int i = 0; i < n; i++) { cin >> id >> x >> y; int dist = x*x + y*y; if(dist > max_dist) { max_id = id; max_dist = dist; } if(dist < min_dist) { min_id = id; min_dist = dist; } } printf("%04d %04d", min_id, max_id); return 0; }

6. 实际应用场景扩展

这个算法虽然简单,但在实际中有很多应用:

  1. 地理位置服务:寻找最近的加油站或餐厅
  2. 游戏开发:检测离玩家最近或最远的NPC
  3. 物联网:选择信号最强或最弱的传感器节点
  4. 物流配送:确定最近的配送点

理解这个简单算法的原理,可以帮助我们在更复杂的场景中应用类似的思想。比如处理三维坐标、加权距离,或者结合其他条件进行筛选。

7. 类似题目推荐

为了巩固这个知识点,可以尝试解决以下类似题目:

  1. PAT乙级1075:链表元素分类 - 也需要维护和更新多个指针
  2. LeetCode 973:最接近原点的K个点 - 扩展为找多个最近点
  3. PAT甲级1011:World Cup Betting - 类似的多条件比较问题
  4. Codeforces 702A:Maximum Increase - 线性扫描维护状态的思想

这些题目都涉及在一次遍历中维护和更新多个状态变量,是算法竞赛中常见的基础题型。

8. 个人经验分享

在解决这类问题时,我总结了一些实用技巧:

  1. 初始值设置:对于求最大值,初始化为理论最小值;对于求最小值,初始化为理论最大值。这比使用第一个元素初始化更可靠。

  2. 避免重复计算:像距离平方这样的值应该先计算存储,而不是在多个if条件中重复计算。

  3. 测试用例设计:除了常规情况,一定要考虑:

    • 所有点相同
    • 只有1个点
    • 最大/最小点在输入序列的开头或结尾
  4. 格式化输出:PAT题目对输出格式要求严格,建议使用printf而不是cout进行格式化输出,特别是需要补零或控制小数位数时。

  5. 变量命名:虽然竞赛中可以简短,但如果有意义的名字会让代码更易读,也减少错误。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询