这C语言得学啊
P1897 电梯里的尴尬
题目
于是,小W便在搭讪大神的同时,也关注着电梯中显示的楼层数字,并且他注意到电梯每向上运行一层需要 6 秒钟,向下运行一层需要 4 秒钟,每开门一次需要 5 秒(如果有人到达才开门),并且每下一个人需要加 1 秒。
特别指出,电梯最开始在 0 层,并且最后必须再回到 0 层才算一趟任务结束。假设在开始的时候已知电梯内的每个人要去的楼层,你能计算出完成本趟任务需要的总时间吗?
这是个很简单的问题,要知道,小W已经修炼到快速心算出结果的境界,现在你来编程试试吧!
输入格式
共 2 行
第 1 行,一个正整数 n,表示乘坐电梯的人数。
第 2 行,n 个正整数,a**i 表示第 i 个人要去的楼层。
输出格式
仅 1 行,一个正整数,表示完成这趟任务需要的时间。
输入输出样例
输入 #1
42 4 3 2输出 #1
59说明/提示
对于 60% 的数据 0<n<104
对于 100% 的数据 0<n<105,0<a**i≤2×107。
源代码
#include <stdio.h>#include <stdlib.h>
#define MAX_PEOPLE 100005
int compare(const void *a, const void *b) { return (*(int*)a - *(int*)b);}
int main() { int n; if (scanf("%d", &n) != 1) return 0;
int floors[MAX_PEOPLE];
for (int i = 0; i < n; i++) { scanf("%d", &floors[i]); }
qsort(floors, n, sizeof(int), compare); int count = 0;
for (int i = 0; i < n; i++) { if (i == 0 || floors[i] != floors[i-1]) { count++; } } int max = floors[n - 1]; long long total_time = (long long)max * 10 + count * 5 + n;
printf("%lld\n", total_time); system("pause"); return 0;}知识点
一.C 语言标准库函数:通用排序 qsort
#include <stdlib.h>...int compare(const void *a, const void *b) { return (*(int*)a - *(int*)b);}...int main{ ... qsort(floors, n, sizeof(int), compare); ...}qsort 是 C 语言标准库 <stdlib.h> 中提供的通用排序函数。它的设计目标是对任何类型的数组进行高效排序 (基于快速排序算法)。
1. 函数原型
2. 四个参数的作用
| 参数 | 作用 | 示例(排序 int 数组) | 核心作用 |
|---|---|---|---|
base | 待排序数组的起始地址。 | floors (数组名) | 告诉 qsort “在哪里排?” |
num | 数组中元素的总数量。 | n (元素总数) | 告诉 qsort “排多少个?” |
size | 单个元素所占的字节大小。 | sizeof(int) | 告诉 qsort “每个数据多大?” |
compar | 自定义的比较函数指针。 | compare (函数名) | 告诉 qsort “如何比较谁大谁小?” |
3. 核心:compare 函数逻辑
qsort 完全依赖 compare 函数的返回值来决定两个元素 (a 和 b) 的相对顺序。
| 返回值 | 逻辑含义 | 排序结果 |
|---|---|---|
| 负数 | a 放在 b 前面。 | |
| 零 | 相对位置不变。 | |
| 正数 | a 放在 b 后面。 |
3.1 升序与降序的实现
实现升序和降序的关键在于 compare 函数内部的减法顺序:
| 排序方向 | 目的 | 实现代码 (整数) |
|---|---|---|
| 升序 (小到大) | 小于 时返回负数。 | return (*(int*)a - *(int*)b); |
| 降序 (大到小) | 小于 时返回正数。 | return (*(int*)b - *(int*)a); |
4. 指针操作解析(compare 内部)
由于 qsort 传入的参数是通用指针 (void *),必须经过以下两个步骤才能取出数值:
| 操作 | 表达式 | 作用 | 类型转换示例 |
|---|---|---|---|
| 类型转换 | (int*)a | 将通用地址视为指向整数的地址。 | const void * const int * |
| 解引用 | *(int*)a | 取出该地址内部存储的实际数值。 | const int * int |
二.关于*(int*)a的使用
int compare(const void *a, const void *b) { return (*(int*)a - *(int*)b);}这个是用于qsort函数排序判断的compare函数
a:在 compare 函数中,a 是一个 const void * 类型的变量。
- 含义: 这是一个通用指针(地址)。它指向内存中的某个位置,但我们不知道这个位置存储的是整数、浮点 数还是结构体。
(int*)a:(int*) 是一个强制类型转换操作符。
- 含义:
(int*)a的结果仍然是一个地址,但它的类型发生了变化。 - 作用: 它是告诉编译器:“我知道
a只是一个通用地址,但请你现在将它视为一个指向整数(int)的地址。” - 结果: 这是一个地址(指针),类型是
int *(或const int *)。
如何获取值?(解引用)
要获取这个地址内部存储的数值,你必须使用解引用运算符 *。
直接是还是太晦涩难懂了,我们通过写一个脚本调试,详细看看这个过程
#include <stdio.h>
// 宏定义颜色代码,让输出更清晰 (如果你的终端支持颜色)#define RED "\x1b[31m"#define GREEN "\x1b[32m"#define YELLOW "\x1b[33m"#define RESET "\x1b[0m"
// 模拟 qsort 使用的 compare 函数int compare_demonstration(const void *a, const void *b) { printf("\n--- 翻译官 (compare) 开始工作 ---\n");
// 1. 初始状态:只知道通用地址 printf(YELLOW "步骤 1: 传入的通用地址 (const void *)\n" RESET); printf(" 地址 A (a): %p\n", a); printf(" 地址 B (b): %p\n", b);
// 2. 强制类型转换:地址的身份确认 const int *ptr_a = (const int *)a; const int *ptr_b = (const int *)b;
printf(YELLOW "步骤 2: 强制类型转换 (const int *)\n" RESET); printf(" 地址 A 现身份 (ptr_a): %p\n", ptr_a); printf(" 地址 B 现身份 (ptr_b): %p\n", ptr_b); printf(" 【注意:地址值没有变,只是编译器知道它们指向 int 了】\n");
// 3. 解引用:获取地址内部存储的数值 int val_a = *ptr_a; int val_b = *ptr_b;
printf(GREEN "步骤 3: 解引用 (*) 取出数值 (int)\n" RESET); printf(" 数值 A (val_a): %d\n", val_a); printf(" 数值 B (val_b): %d\n", val_b);
// 4. 比较:返回整数差值 int result = val_a - val_b; printf(RED "步骤 4: 比较并返回结果 (val_a - val_b)\n" RESET); printf(" 返回结果: %d\n", result);
if (result < 0) { printf(" 【结果为负,qsort会认为 %d 应该在 %d 之前】\n", val_a, val_b); } else { printf(" 【结果为正/零,qsort会认为 %d 应该在 %d 之后】\n", val_a, val_b); }
return result;}
int main() { // 模拟数组中的两个元素 int num1 = 10; int num2 = 25;
printf("--- 主程序 (main) 初始化数据 ---\n"); printf("数值 num1 = %d (地址: %p)\n", num1, &num1); printf("数值 num2 = %d (地址: %p)\n", num2, &num2);
// 模拟 qsort 调用 compare 函数,传入的是 num1 和 num2 的地址 // 注意:qsort 传入的都是地址,所以我们要使用 & 符号 compare_demonstration(&num1, &num2);
// 模拟第二次调用,调换顺序 compare_demonstration(&num2, &num1);
return 0;}运行结果

这道题本身的逻辑不难,主要就是这些实现方法以前没有接触过,指针学得太潦草
部分信息可能已经过时









