题解:洛谷 P5738 歌唱比赛
【题目来源】
【题目描述】
\(n(n\le 100)\) 名同学参加歌唱比赛,并接受 \(m(m\le 20)\) 名评委的评分,评分范围是 \(0\) 到 \(10\) 分。这名同学的得分就是这些评委给分中去掉一个最高分,去掉一个最低分,剩下 \(m-2\) 个评分的平均数。请问得分最高的同学分数是多少?评分保留 \(2\) 位小数。
【输入】
第一行两个整数 \(n,m\)。
接下来 \(n\) 行,每行各 \(m\) 个整数,表示得分。
【输出】
输出分数最高的同学的分数,保留两位小数。
【输入样例】
7 6
4 7 2 6 10 7
0 5 0 10 3 10
2 6 8 4 3 6
6 3 6 7 5 8
5 9 3 3 8 1
5 9 9 3 2 0
5 8 0 4 1 10
【输出样例】
6.00
【核心思想】
-
问题分析:有 \(n\) 名同学参加歌唱比赛,每名同学有 \(m\) 个评委的评分(\(0 \sim 10\) 分)。每名同学的最终得分为去掉一个最高分和一个最低分后的平均分。需要求出所有同学中最高得分,并保留两位小数。本质是多组数据的最值统计与平均值计算问题,核心是每组数据需要去掉极值后求平均,然后取最大值。
-
算法选择:
- 逐组处理 + 动态维护:对每组 \(m\) 个评分,在输入过程中同时记录总和、最大值和最小值,输入完成后即可计算去掉极值后的平均值。这样无需存储所有评分,节省空间。
- 复杂度:时间复杂度 \(O(n \times m)\),空间复杂度 \(O(1)\)。
-
关键步骤:
- 读入:读取 \(n\) 和 \(m\),初始化最高得分
max_score = -1。 - 处理每组数据:
- 读取第一个评分,初始化
sum、max_val、min_val。 - 继续读取剩余 \(m-1\) 个评分,更新
sum、max_val、min_val。 - 计算去掉最高分和最低分后的平均分:
avg = (sum - max_val - min_val) / (m - 2)。 - 若
avg > max_score,更新max_score。
- 读取第一个评分,初始化
- 输出:
printf("%.2f", max_score)。
- 读入:读取 \(n\) 和 \(m\),初始化最高得分
-
时间/空间复杂度:
- 时间复杂度:\(O(n \times m)\),\(n \le 100, m \le 20\),非常快。
- 空间复杂度:\(O(1)\),仅使用几个变量。
-
模拟与数据处理:
- 流式处理:在输入过程中直接计算,无需保存所有评分,这是处理大量数据时的常用技巧。
- 极值维护:同时维护最大值和最小值,以便最后剔除。
- 类型转换:计算平均值时,使用
1.0 * sum / (m - 2)确保得到浮点数结果。 - 适用场景:这类“多组数据统计”问题在竞赛中非常常见,练习了循环、条件判断和基本算术运算。
【算法标签】
普及- #模拟
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
/**
* 计算单个选手的最终得分(去掉最高分和最低分后的平均分)
* @param m 评委人数
* @return 选手的最终得分
*/
double judge(int m)
{
int max, min, sum = 0, tmp; // 定义变量:最高分、最低分、总分、临时分数
double ans; // 定义变量:最终得分
// 读取第一个评委的分数
cin >> tmp;
max = tmp; // 初始化最高分
min = tmp; // 初始化最低分
sum = tmp; // 初始化总分
// 读取剩余评委的分数
for (int i = 2; i <= m; i++)
{
cin >> tmp;
if (tmp > max) max = tmp; // 更新最高分
if (tmp < min) min = tmp; // 更新最低分
sum += tmp; // 累加总分
}
// 计算去掉最高分和最低分后的总分
sum -= max + min;
// 计算平均分(保留两位小数)
ans = 1.0 * sum / (m - 2);
return ans; // 返回最终得分
}
int main()
{
int n, m; // 定义变量:选手人数n,评委人数m
double ans = -1; // 定义变量:最高得分,初始为-1
double tmp; // 定义变量:临时存储得分
cin >> n >> m; // 输入选手人数和评委人数
// 计算每位选手的得分,并找出最高分
for (int i = 1; i <= n; i++)
{
tmp = judge(m); // 计算当前选手得分
if (ans < tmp) // 更新最高得分
{
ans = tmp;
}
}
// 输出最高得分,保留两位小数
printf("%.2f", ans);
return 0; // 程序正常结束
}
【运行结果】
7 6
4 7 2 6 10 7
0 5 0 10 3 10
2 6 8 4 3 6
6 3 6 7 5 8
5 9 3 3 8 1
5 9 9 3 2 0
5 8 0 4 1 10
6.00
浙公网安备 33010602011771号