一所学校里有一些班级,每个班级里有一些学生,现在每个班都会进行一场期末考试。给你一个二维数组 classes
,其中 classes[i] = [passi, totali]
,表示你提前知道了第 i
个班级总共有 totali
个学生,其中只有 passi
个学生可以通过考试。
给你一个整数 extraStudents
,表示额外有 extraStudents
个聪明的学生,他们 一定 能通过任何班级的期末考。你需要给这 extraStudents
个学生每人都安排一个班级,使得 所有 班级的 平均 通过率 最大 。
一个班级的 通过率 等于这个班级通过考试的学生人数除以这个班级的总人数。平均通过率 是所有班级的通过率之和除以班级数目。
请你返回在安排这 extraStudents
个学生去对应班级后的 最大 平均通过率。与标准答案误差范围在 10-5
以内的结果都会视为正确结果。
示例 1:
输入:classes = [[1,2],[3,5],[2,2]], extraStudents
= 2
输出:0.78333
解释:你可以将额外的两个学生都安排到第一个班级,平均通过率为 (3/4 + 3/5 + 2/2) / 3 = 0.78333 。
示例 2:
输入:classes = [[2,4],[3,9],[4,5],[2,10]], extraStudents
= 4
输出:0.53485
提示:
1 <= classes.length <= 105
classes[i].length == 2
1 <= passi <= totali <= 105
1 <= extraStudents <= 105
代码
#include <stdlib.h>
double maxAverageRatio(int** classes, int classesSize, int* classesColSize, int extraStudents) {
if (classesSize == 0) return 0.0;
// 初始化存储每个班级通过人数和总人数的数组
int* passes = (int*)malloc(classesSize * sizeof(int));
int* totals = (int*)malloc(classesSize * sizeof(int));
for (int i = 0; i < classesSize; i++) {
passes[i] = classes[i][0];
totals[i] = classes[i][1];
}
// 定义堆节点结构(存储负增益和班级索引)
typedef struct {
double neg_gain;
int idx;
} HeapNode;
HeapNode* heap = (HeapNode*)malloc(classesSize * sizeof(HeapNode));
int heapSize = 0;
// 初始化堆:计算每个班级的初始增益并插入堆
for (int i = 0; i < classesSize; i++) {
int pass = passes[i];
int total = totals[i];
double gain = 0.0;
if (total > pass) {
gain = (double)(total - pass) / ((double)total * (total + 1));
}
// 插入堆(使用负增益构建最小堆)
int cur = heapSize++;
heap[cur].neg_gain = -gain;
heap[cur].idx = i;
// 上浮操作维护堆性质
while (cur > 0) {
int parent = (cur - 1) / 2;
if (heap[parent].neg_gain > heap[cur].neg_gain) {
HeapNode temp = heap[parent];
heap[parent] = heap[cur];
heap[cur] = temp;
cur = parent;
} else break;
}
}
// 分配额外学生
for (int k = 0; k < extraStudents; k++) {
// 提前终止:若堆顶增益接近0(无法再提升)
if (-heap[0].neg_gain < 1e-9) break;
// 弹出堆顶元素(增益最大的班级)
HeapNode top = heap[0];
heap[0] = heap[--heapSize];
// 下沉操作维护堆性质
int cur = 0;
while (1) {
int left = 2 * cur + 1;
int right = 2 * cur + 2;
int smallest = cur;
if (left < heapSize && heap[left].neg_gain < heap[smallest].neg_gain) {
smallest = left;
}
if (right < heapSize && heap[right].neg_gain < heap[smallest].neg_gain) {
smallest = right;
}
if (smallest != cur) {
HeapNode temp = heap[cur];
heap[cur] = heap[smallest];
heap[smallest] = temp;
cur = smallest;
} else break;
}
// 更新该班级数据
int idx = top.idx;
passes[idx]++;
totals[idx]++;
// 重新计算增益
double new_gain = 0.0;
int new_pass = passes[idx];
int new_total = totals[idx];
if (new_total > new_pass) {
new_gain = (double)(new_total - new_pass) / ((double)new_total * (new_total + 1));
}
// 重新插入堆
int cur_index = heapSize++;
heap[cur_index].neg_gain = -new_gain;
heap[cur_index].idx = idx;
while (cur_index > 0) {
int parent = (cur_index - 1) / 2;
if (heap[parent].neg_gain > heap[cur_index].neg_gain) {
HeapNode temp = heap[parent];
heap[parent] = heap[cur_index];
heap[cur_index] = temp;
cur_index = parent;
} else break;
}
}
// 计算平均通过率
double total_rate = 0.0;
for (int i = 0; i < classesSize; i++) {
total_rate += (double)passes[i] / (double)totals[i];
}
double average = total_rate / classesSize;
// 释放内存
free(passes);
free(totals);
free(heap);
return average;
}