Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
1664 字
8 分钟
洛谷刷题01
2025-12-10
C

这C语言得学啊

P1897 电梯里的尴尬#

题目#

于是,小W便在搭讪大神的同时,也关注着电梯中显示的楼层数字,并且他注意到电梯每向上运行一层需要 6 秒钟,向下运行一层需要 4 秒钟,每开门一次需要 5 秒(如果有人到达才开门),并且每下一个人需要加 1 秒。

特别指出,电梯最开始在 0 层,并且最后必须再回到 0 层才算一趟任务结束。假设在开始的时候已知电梯内的每个人要去的楼层,你能计算出完成本趟任务需要的总时间吗?

这是个很简单的问题,要知道,小W已经修炼到快速心算出结果的境界,现在你来编程试试吧!

输入格式#

共 2 行

第 1 行,一个正整数 n,表示乘坐电梯的人数。

第 2 行,n 个正整数,a**i 表示第 i 个人要去的楼层。

输出格式#

仅 1 行,一个正整数,表示完成这趟任务需要的时间。

输入输出样例#

输入 #1

4
2 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. 函数原型#

void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *));\texttt{void qsort(void *base, size\_t num, size\_t size, int (*compar)(const void *, const void *));}

2. 四个参数的作用#

参数作用示例(排序 int 数组)核心作用
base待排序数组的起始地址floors (数组名)告诉 qsort “在哪里排?”
num数组中元素的总数量n (元素总数)告诉 qsort “排多少个?”
size单个元素所占的字节大小sizeof(int)告诉 qsort “每个数据多大?”
compar自定义的比较函数指针compare (函数名)告诉 qsort “如何比较谁大谁小?”

3. 核心:compare 函数逻辑#

qsort 完全依赖 compare 函数的返回值来决定两个元素 (ab) 的相对顺序。

返回值逻辑含义排序结果
负数a<ba < ba 放在 b 前面
a=ba = b相对位置不变。
正数a>ba > ba 放在 b 后面
3.1 升序与降序的实现#

实现升序和降序的关键在于 compare 函数内部的减法顺序:

排序方向目的实现代码 (整数)
升序 (小到大)aa 小于 bb 时返回负数。return (*(int*)a - *(int*)b);
降序 (大到小)aa 小于 bb 时返回正数。return (*(int*)b - *(int*)a);

4. 指针操作解析(compare 内部)#

由于 qsort 传入的参数是通用指针 (void *),必须经过以下两个步骤才能取出数值:

操作表达式作用类型转换示例
类型转换(int*)a将通用地址视为指向整数的地址。const void * \to const int *
解引用*(int*)a取出该地址内部存储的实际数值const int * \to 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;
}

运行结果

image-20251210230212835

这道题本身的逻辑不难,主要就是这些实现方法以前没有接触过,指针学得太潦草

洛谷刷题01
https://btop251.vercel.app/posts/c语言学习/洛谷刷题01/
作者
btop251
发布于
2025-12-10
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时