L2-003 月饼
#include <stdio.h> #include <stdlib.h> // 定义月饼结构体 typedef struct { double stock; // 库存量(万吨) double total_price; // 总售价(亿元) double unit_price; // 单位售价(亿元/万吨) } Mooncake; // 比较函数,用于排序(按单位售价从高到低) int compare(const void *a, const void *b) { Mooncake *m1 = (Mooncake *)a; Mooncake *m2 = (Mooncake *)b; if (m1->unit_price > m2->unit_price) return -1; // 降序排列 if (m1->unit_price < m2->unit_price) return 1; return 0; } int main() { int N, D; scanf("%d %d", &N, &D); // 输入月饼种类数和市场需求量 Mooncake mooncakes[N]; // 定义月饼数组 // 输入每种月饼的库存量 for (int i = 0; i < N; i++) { scanf("%lf", &mooncakes[i].stock); } // 输入每种月饼的总售价 for (int i = 0; i < N; i++) { scanf("%lf", &mooncakes[i].total_price); } // 计算每种月饼的单位售价 for (int i = 0; i < N; i++) { mooncakes[i].unit_price = mooncakes[i].total_price / mooncakes[i].stock; } // 按单位售价从高到低排序 qsort(mooncakes, N, sizeof(Mooncake), compare); double max_profit = 0.0; // 最大收益 double remaining_demand = D; // 剩余需求量 // 贪心选择:优先销售单位售价高的月饼 for (int i = 0; i < N; i++) { if (remaining_demand <= 0) break; // 如果需求量已满足,退出循环 if (mooncakes[i].stock <= remaining_demand) { // 如果当前月饼库存量 <= 剩余需求量,全部卖出 max_profit += mooncakes[i].total_price; remaining_demand -= mooncakes[i].stock; } else { // 如果当前月饼库存量 > 剩余需求量,卖出部分 max_profit += mooncakes[i].unit_price * remaining_demand; remaining_demand = 0; // 需求量已满足 } } // 输出最大收益,精确到小数点后 2 位 printf("%.2f\n", max_profit); return 0; }
int compare(const void *a, const void *b)
这行代码定义了一个名为 compare
的函数,它是一个 比较函数,通常用于与 C 标准库中的 qsort
函数配合使用。
1. 返回值
- 返回值类型是 int。
- 返回值用于指示两个元素的相对顺序:如果返回值 小于 0,表示第一个参数 a 应该排在第二个参数 b 前面。如果返回值 大于 0,表示第一个参数 a 应该排在第二个参数 b 后面。如果返回值 等于 0,表示两个参数相等,顺序不变。
2. 参数
- 参数类型是 const void *,即 指向任意类型的常量指针。const 表示指针指向的数据是常量,不能在函数内修改。void * 是泛型指针,可以指向任意类型的数据。
- 参数 a 和 b 分别指向需要比较的两个元素。
为什么使用 const void *
?
- 泛型设计:qsort 是一个通用的排序函数,可以对任意类型的数组进行排序。为了支持任意类型,qsort 使用 void * 作为参数类型,允许传递任意类型的指针。
- 安全性:const 确保比较函数不会修改指针指向的数据,保证数据的安全性。
qsort(mooncakes, N, sizeof(Mooncake), compare);
参数详解
1. mooncakes
- 这是待排序的数组,类型是 Mooncake 结构体数组。
- mooncakes 是数组的起始地址,传递给 qsort 时会被隐式转换为 void * 类型。
2. N
- 这是数组 mooncakes 的元素个数。
- 例如,如果 mooncakes 数组有 3 个月饼,则 N = 3。
3. sizeof(Mooncake)
- 这是每个元素的大小(以字节为单位)。
- sizeof(Mooncake) 计算 Mooncake 结构体占用的字节数。
- 例如,如果 Mooncake 结构体包含 3 个 double 字段,则 sizeof(Mooncake) 可能是 24 字节(假设 double 占 8 字节)。
4. compare
- 这是比较函数的指针,用于定义排序规则。
- compare 函数的参数类型必须是 const void *,返回值必须是 int。
- qsort 会调用 compare 函数来比较数组中的元素。
排序过程
- 初始化:qsort 接收数组 mooncakes、元素个数 N、元素大小 sizeof(Mooncake) 和比较函数 compare。
- 比较和交换:qsort 内部使用快速排序算法(或其他高效的排序算法)对数组进行排序。在排序过程中,qsort 会多次调用 compare 函数来比较数组中的元素。
- 排序完成:排序完成后,数组 mooncakes 中的元素会按照 compare 函数定义的规则排列。
在C语言中,结构体指针访问成员需要使用箭头运算符 ->,而结构体变量访问成员使用点运算符 .。以下是详细解释:
为什么不能将 m1->unit_price 改成 m1.unit_price?
指针与变量的区别:
m1 和 m2 是 Mooncake 类型的指针(Mooncake*),它们指向结构体的内存地址。
如果直接写 m1.unit_price,相当于试图通过指针变量(m1)直接访问成员,但指针本身并不是结构体实例,语法错误。
正确的访问方式:
指针访问成员:必须用 ->(等价于 (*m1).unit_price)。
变量访问成员:如果 m1 是结构体变量(如 Mooncake m1;),则可以用 .
用 ->:当操作对象是结构体指针时(如 Mooncake*)。
用 .:当操作对象是结构体变量时(如 Mooncake m1;)。