题解:洛谷 P5728 旗鼓相当的对手
【题目来源】
【题目描述】
现有 \(N\) 名同学参加了期末考试,并且获得了每名同学的信息:语文、数学、英语成绩(均为不超过 \(150\) 的自然数)。如果某对学生 <\(i,j\)> 的每一科成绩的分差都不大于 \(5\),且总分分差不大于 \(10\),那么这对学生就是“旗鼓相当的对手”。现在想知道这些同学中,有几对“旗鼓相当的对手”?同样一个人可能会和其他好几名同学结对。
【输入】
第一行一个正整数 \(N\)。
接下来 \(N\) 行,每行三个整数,其中第 \(i\) 行表示第 \(i\) 名同学的语文、数学、英语成绩。最先读入的同学编号为 \(1\)。
【输出】
输出一个整数,表示“旗鼓相当的对手”的对数。
【输入样例】
3 90 90 90 85 95 90 80 100 91
【输出样例】
2
【核心思想】
-
问题分析:给定 \(N\) 名学生的语文、数学、英语成绩,需要统计有多少对学生满足:每门学科的分差都不大于 5,且总分分差不大于 10。本质是一个枚举所有组合并进行条件判断的问题,由于 \(N\) 通常不大,直接使用双重循环即可。
-
算法选择:
- 双重循环枚举:遍历所有学生组合 \((i, j)\)(\(1 \le i < j \le N\)),对每对组合检查四个条件(三科分差 \(\le 5\) 且总分分差 \(\le 10\))。时间复杂度 \(O(N^2)\),对于 \(N \le 1000\) 是完全可以接受的。
- 数据结构优化(可选):如果需要处理更大的 \(N\),可以尝试按总分排序后使用双指针,但本题数据范围下双重循环是最直接且足够高效的方案。
-
关键步骤:
- 读入与存储:读取 \(N\),并用三个数组
yu、shu、yin分别存储每名学生的三科成绩,同时计算总分存入sum数组。 - 枚举组合:外层循环 \(i\) 从 \(1\) 到 \(N\),内层循环 \(j\) 从 \(i+1\) 到 \(N\)。
- 条件判断:使用
abs()函数计算绝对差,检查:abs(yu[i] - yu[j]) <= 5abs(shu[i] - shu[j]) <= 5abs(yin[i] - yin[j]) <= 5abs(sum[i] - sum[j]) <= 10
- 计数与输出:若所有条件满足,则
ans++;最后输出ans。
- 读入与存储:读取 \(N\),并用三个数组
-
时间/空间复杂度:
- 时间复杂度:\(O(N^2)\),\(N\) 通常 \(\le 1000\),可接受。
- 空间复杂度:\(O(N)\),用于存储成绩和总分。
-
模拟与枚举:
- 组合枚举:使用 \(i\) 从 \(1\) 到 \(N\)、\(j\) 从 \(i+1\) 到 \(N\) 的方式,可以避免重复计数(每对只计算一次)。
- 多条件判断:所有条件必须同时满足,因此使用逻辑与(
&&)连接。 - 绝对差计算:使用
abs()函数可以简洁地判断差值的绝对值是否在范围内。 - 适用场景:这类“统计满足多重条件的配对数量”问题,在数据规模较小时,双重循环是最直接、最可靠的解决方法。
【算法标签】
入门 #模拟
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
/**
* 主函数 - 程序入口
* @return 程序执行状态码(0表示成功)
*/
int main()
{
int n; // 定义变量:学生人数
int yu[1005]; // 定义数组:存储语文成绩
int shu[1005]; // 定义数组:存储数学成绩
int yin[1005]; // 定义数组:存储英语成绩
int sum[1005]; // 定义数组:存储总分
int ans = 0; // 定义变量:符合条件的对手对数
cin >> n; // 输入学生人数
// 输入每个学生的三科成绩并计算总分
for (int i = 1; i <= n; i++)
{
cin >> yu[i] >> shu[i] >> yin[i];
sum[i] = yu[i] + shu[i] + yin[i];
}
// 遍历所有学生组合,统计符合条件的对手对数
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
// 旗鼓相当的对手判定条件:
// 1. 各科成绩差不超过5分
// 2. 总分差不超过10分
if (abs(yu[i] - yu[j]) <= 5 &&
abs(shu[i] - shu[j]) <= 5 &&
abs(yin[i] - yin[j]) <= 5 &&
abs(sum[i] - sum[j]) <= 10)
{
ans++; // 符合条件的对手对数加1
}
}
}
cout << ans << endl; // 输出结果
return 0; // 程序正常结束
}
【运行结果】
3
90 90 90
85 95 90
80 100 91
2
浙公网安备 33010602011771号