评委打分算法解析:从基础实现到性能优化(洛谷)
题目核心考点解析
这道题目主要考察以下几个核心编程能力:
1. 数组处理与极值查找(⭐⭐⭐⭐⭐)
- 极值定位:在数组中查找最大值和最小值
- 元素过滤:排除特定元素后的数组处理
- 遍历算法:数组元素的顺序访问与处理
2. 数学计算与精度控制(⭐⭐⭐⭐)
- 平均数计算:求和与除法运算
- 精度格式化:保留两位小数的输出控制
- 整数除法陷阱:避免整数除法导致精度丢失
3. 边界条件处理(⭐⭐⭐)
- 重复极值处理:多个相同最大值/最小值的处理
- 数据范围验证:输入数据的合法性检查
- 特殊情况处理:最小评委数的情况
解法实现与代码分析
基础解法:直观实现
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
using namespace std;double calculateScore(vector<int>& scores) {int min_score = *min_element(scores.begin(), scores.end());int max_score = *max_element(scores.begin(), scores.end());int sum = 0;bool min_removed = false, max_removed = false;for(int score : scores) {if(!min_removed && score == min_score) {min_removed = true;continue;}if(!max_removed && score == max_score) {max_removed = true;continue;}sum += score;}return (double)sum / (scores.size() - 2);
}int main() {int n;cin >> n;vector<int> scores(n);for(int i=0; i<n; i++) {cin >> scores[i];}double result = calculateScore(scores);cout << fixed << setprecision(2) << result;return 0;
}
优化解法:单次遍历
#include <iostream>
#include <iomanip>
#include <climits>
using namespace std;int main() {int n;cin >> n;int min_val = INT_MAX, max_val = INT_MIN;int sum = 0;for(int i=0; i<n; i++) {int score;cin >> score;sum += score;if(score < min_val) min_val = score;if(score > max_val) max_val = score;}double avg = (sum - min_val - max_val) / (double)(n - 2);cout << fixed << setprecision(2) << avg;return 0;
}
关键知识点详解
1. 极值查找算法
// 方法1:使用STL算法
int min_val = *min_element(scores.begin(), scores.end());
int max_val = *max_element(scores.begin(), scores.end());// 方法2:手动遍历查找
int min_val = INT_MAX, max_val = INT_MIN;
for(int score : scores) {if(score < min_val) min_val = score;if(score > max_val) max_val = score;
}
2. 精度控制技巧
// 关键输出控制
cout << fixed << setprecision(2) << result;
fixed
:固定小数位数显示setprecision(2)
:设置小数点后2位- 需要包含
<iomanip>
头文件
3. 重复极值处理策略
题目说明"只需要去掉一个",因此:
- 找到第一个最小值并排除
- 找到第一个最大值并排除
- 其余相同极值保留在计算中
测试用例与验证
测试案例 | 输入 | 预期输出 | 验证要点 |
---|---|---|---|
基础测试 | 5 [9,5,6,8,9] | 7.67 | 样例验证 |
重复极值 | 6 [10,10,9,8,7,7] | 8.25 | 重复极值处理 |
最小评委 | 3 [5,5,5] | 5.00 | 最小边界情况 |
极端分数 | 4 [0,10,5,5] | 5.00 | 0分和10分处理 |
大数量级 | 1000 [全5分] | 5.00 | 性能测试 |
常见错误与修正
错误1:整数除法问题
// 错误写法:整数除法导致精度丢失
int avg = (sum - min - max) / (n - 2);
修正:强制转换为浮点数除法
double avg = (sum - min - max) / (double)(n - 2);
错误2:重复极值全排除
// 错误写法:排除了所有极值
if(score == min_val || score == max_val) continue;
修正:仅排除第一个遇到的极值
错误3:未处理n=3的情况
// 错误写法:未考虑n-2=1的情况
double avg = sum / (n - 2); // 当n=3时除数为1
修正:虽然n≥3,但仍需保证计算正确
竞赛技巧总结
- 极值查找优化:使用单次遍历同时找最小最大值
- 精度控制前置:在计算前就考虑类型转换
- 空间效率:可以不用存储所有分数,实时处理
- 边界测试:特别注意n=3和全同分数的情况
拓展练习
变形练习1:去掉所有最高最低分后求平均
- 需要统计极值出现次数
- 修改分母为
n - min_count - max_count
变形练习2:加权平均分
- 给不同评委设置权重
- 计算加权平均值
进阶挑战:在线处理模式
- 不存储所有分数
- 实时维护sum、min、max
"算法竞赛中,数据处理的关键在于理解题目要求的本质,而非表面描述" —— 通过这道题,我们深入理解了极值处理和精度控制的精髓
关注并私信【裁判打分】可获得:
- C++数值精度控制指南