平均分排序
1 条题解
-
0
P4617 平均分排序(基础)
解题思路
这道题要把学生按平均分从低到高排序,并保留一位小数输出。平均分里面藏着小技巧,分四步讲清楚。
第一步,发现一个"偷懒"的办法。 平均分 = 三门总分 ÷ 3,每名学生都是除以同一个 3,所以"平均分低的"和"总分低的"完全等价。干脆不比平均分,直接比总分,全程都是整数运算,又准又快,还不用怕浮点数比较出误差。
第二步,用结构体装好学号和总分。 结构体 Student 保存学号和总分。读入三门成绩后立刻算出总分存进去,排序时按总分从小到大排。题目保证每个学生的平均分都不相同,所以总分也不会相同,不需要处理并列。
第三步,用整数技巧算一位小数。 输出要保留一位小数,直接用 double 有浮点误差风险。换整数思路:总分除以 3 的商是整数部分;余数只有 0、1、2,分别对应小数点后的 .0、.333……、.666……,四舍五入到一位就是 .0、.3、.7。代码用
(score % 3 * 10 + 1) / 3算出十分位。比如总分 170:170/3 = 56 余 2,(2×10+1)/3 = 7,输出 56.7;样例第 1 个学生总分 190:190/3 = 63 余 1,(1×10+1)/3 = 3,输出 63.3;再比如总分 180:180/3 = 60 余 0,(0×10+1)/3 = 0,输出 60.0。第四步,排序后输出。 用 sort() 按总分从小到大排好,然后逐个输出学号、空格、平均分和换行。
**回顾总结。**这道题有两个巧劲:一是"平均分低等于总分低",所以排序只比整数总分;二是"一位小数用余数算",把浮点误差彻底消灭在整数运算里。不管总分多大,商和余数都能用整除和取余一步算出来,记住余数 0、1、2 对应 .0、.3、.7,再套公式就能稳稳输出。
参考代码
// 平均分排序:按三门成绩平均分从低到高排列学生,输出平均分(保留1位小数) #include <iostream> #include <algorithm> using namespace std; // 保存一名学生的学号和三门成绩总分 struct Student { int id; // 学号 int score; // 三门总分 }; // 自定义比较函数:总分(即平均分)从低到高 bool cmp(const Student &a, const Student &b) { return a.score < b.score; } // 输出平均分(保留 1 位小数),用整数运算避免浮点误差 void printAvg(int score) { cout << score / 3 << '.'; // 整数部分 cout << (score % 3 * 10 + 1) / 3; // 十分位:四舍五入 } int main() { int n; Student students[105]; cin >> n; for (int i = 0; i < n; i++) { int chinese, math, english; cin >> students[i].id >> chinese >> math >> english; students[i].score = chinese + math + english; // 计算总分 } sort(students, students + n, cmp); // 按平均分从低到高排序 for (int i = 0; i < n; i++) { cout << students[i].id << ' '; printAvg(students[i].score); cout << endl; } return 0; }复杂度分析
排序用 sort(),时间复杂度是 O(n log n),n 不超过 100。结构体数组占用的空间是 O(n)。整数四舍五入的每一步都是 O(1),而且完全避免了浮点误差,运行速度非常快。
- 1