题解
节省时间
1 条题解
-
0
P4799 节省时间(入门)
解题思路
-
读懂题目:学生排队找老师答疑,每个学生有一个预估答疑时长。答疑完成时间 = 自己答疑时间 + 等前面同学的时间。题目要求安排排队顺序,让所有学生的"平均完成时间"最少,结果保留两位小数。
-
打个比方:就像去医院排队抽血,每个人检查要花不同的时间。如果检查慢的人排在前面,后面所有人都要陪着他等;检查快的人排前面,大家都能早一点完成。所以要把答疑时间短的同学排在前面。
-
贪心结论:把答疑时长从小到大排序,就是最优顺序,平均完成时间最小。
-
怎么计算平均完成时间:排好队后,第 1 位同学完成时间是自己的时长 t₁;第 2 位同学要等第 1 位,自己再答疑,完成时间是 t₁+t₂;第 3 位是 t₁+t₂+t₃……也就是第 i 位同学的完成时间等于"前 i 位同学答疑时长的总和"(前缀和)。把所有完成时间加起来,除以学生人数,就是平均完成时间。
-
看例子:样例答疑时长 3,1,2,6,排序后是 1,2,3,6。完成时间依次是 1、1+2=3、1+2+3=6、1+2+3+6=12,总和是 1+3+6+12=22,22÷4=5.50,和答案一致。
-
和哪题类似:这道题和"排队打水""排队接水"是同一类问题,都是让时间短的人先来,从而让平均等待时间最小。
-
边界情况:n=1 时平均完成时间就是他自己答疑的时间;n 最多 1000,时长最多 2000,总完成时间可能很大,所以代码里用 long long 累加,防止整数溢出,最后再转成浮点数除以人数。
参考代码
// P4799 节省时间:答疑短的排前面,所有人平均完成时间最少 #include <iostream> using namespace std; int dur[1005]; // 每位学生的预估答疑时长 int main() { int n; cin >> n; for (int i = 0; i < n; i++) cin >> dur[i]; // 答疑时长升序排序(冒泡排序,短的排前面) for (int i = 0; i < n - 1; i++) for (int j = 0; j < n - 1 - i; j++) if (dur[j] > dur[j + 1]) { int temp = dur[j]; dur[j] = dur[j + 1]; dur[j + 1] = temp; } long long total = 0; // 所有人完成答疑的时间总和 long long sum = 0; // 前面同学的答疑时间总和 for (int i = 0; i < n; i++) { sum += dur[i]; // 等前面同学的时间 + 自己的答疑时间 total += sum; // 这就是第 i 位同学的完成时间 } printf("%.2f\n", (double)total / n); return 0; }复杂度分析
冒泡排序的时间是 O(n²),n≤1000,大约一百万次比较,很快;计算前缀和只需要扫一遍数组,是 O(n)。空间上只用了一个长度为 1005 的数组,是 O(n)。整体程序轻巧,轻松通过所有测试点。
-
- 1