G - 考试排名 题解 by Aze

1. 要点

  • 结构体 struct 数组的应用

  • 排序 的应用

  • 多重条件排序

  • %-10s 格式化输出

  • 比较复杂的输入处理

2. 前置知识

  • 结构体数组

    • struct的声明,使用

    • 跟数组的区别

  • 冒泡排序(sort也行,我用的快排但思路不太好讲)

3.题目

C++编程考试使用的实时提交系统,具有即时获得成绩排名的特点。它的功能是怎么实现的呢?

我们做好了题目的解答,提交之后,要么“AC”,要么错误,不管怎样错法,总是给你记上一笔,表明你曾经有过一次错误提交,因而当你一旦提交该题“AC”后,就要与你算一算帐了,总共该题错误提交了几回。

虽然你在题数上,大步地跃上了一个台阶,但是在耗时上要摊上你共花去的时间。

特别是,曾经有过的错误提交,每次都要摊上一定的单位时间分。

这样一来,你在做出的题数上,可能领先别人很多,但是,在做出同样题数的人群中,你可能会在耗时上处于排名的劣势。

例如:

某次考试一共8题(A,B,C,D,E,F,G,H),每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数,但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上一对括号,里面有个整数b,那就表示该学生提交该题AC了,耗去了时间a,同时,曾经错误提交了b次,因此对于下述输入数据:

若每次错误提交的罚分为20分,则其排名从高到低应该是这样的: Josephus 5 376 John 4 284 Alice 4 352 Smith 3 167 Bob 2 325 Bush 0 0

input:

8 20
Smith     -1    -16 8   0   0   120 39  0
John      116   -2  11  0   0   82  55(1)   0
Josephus  72(3) 126 10  -3  0   47  21(2)   -2
Bush      0 -1  -8  0   0   0   0   0
Alice     -2    67(2)   13  -1  0   133 79(1)   -1
Bob   0 0   57(5)   0   0   168 -7  0

output:

Josephus    5  376
John        4  284
Alice       4  352
Smith       3  167
Bob         2  325
Bush        0    0

4.分析

输出什么结果?

每个人根据 AC题目数 和 时间 进行排名,输出排名列表

既然我们需要进行排序之后再输出,就必须设计一个数据结构来存储这些信息

并且每个人的 AC题目数 和 时间 都是要跟个人绑定的

所以,struct 是最优选择(大概)

struct student{char name[11]; // 题上说最长11个字符int AC = 0;int time = 0; // 直接初始化为0
}
student stu[100020]; // 创建含100020个结构体的数组

数据结构选好之后,开始考虑如何把数据存进去

第一行 n,m 没问题直接读,n 代表题数,m 代表罚时,也就是说,人数是不知道有多少的

所以 用 while(scanf()) 来读每一行

因为后面题数是跟 n 相关,得用 for 计次循环

结合一下,先用while读名字,再用for读成绩

每次循环读入一个人的成绩

while(scanf("%s",&stu[i].name) != EOF)
{for(int j = 0; j < n; j++){}i++; // ++后下次循环 就读入 下一个人的成绩
}

接着来看怎么读成绩,有三种情况

  • 正数:一次作对,AC++

  • 负数:没做出来

  • 正数+括号:有做错的,罚时,AC++

那么time是怎么计算的呢?

抓一个分析分析:

Smith     -1    -16 8   0   0   120 39  0
//做出来三道题,总时间为 120 + 39 + 8 = 167
//所以很明显,如果没做出来是不计入时间的 

既然如此,当读入一个负数时直接跳过循环,去读下一个数就好

int score;
scanf("%d",&score);
if(score < 0) continue;

然后是处理 正数+括号,因为scanf("%d")碰到非数字会停下,所以读入后可以接 getchar()判断后一个字符是空格还是左括号(,是括号就特殊处理,不然就直接继续循环

int score;
scanf("%d",&score);
if(score < 0) continue;
if(getchar() == '(') // 判断是否有左括号
{//.....罚时计算
}
gerchar(); // 吸收右括号

数据是这么读,然后将其处理一下再存入

int score;
scanf("%d",&score);
if(score <= 0) continue;
stu[i].time += score;
if(getchar() == '(') // 判断是否有左括号
{int failed;scanf("%d",&failed);stu[i].time += failed * m; // 加上罚时
}
gerchar(); // 吸收右括号
stu[i].AC++; // 如果能运行到这说明已经不是负数或者0,这题他整出来了

结合一下

int i = 0;
while(scanf("%s",&stu[i].name) != EOF)
{for(int j = 0; j < n; j++){int score;scanf("%d",&score);if(score <= 0) continue;stu[i].time += score;if(getchar() == '(') // 判断是否有左括号{int failed;scanf("%d",&failed); stu[i].time += failed * m; // 加上罚时}gerchar(); // 吸收右括号stu[i].AC++; // 如果能运行到这说明已经不是负数或者0,这题他整出来了}i++; // ++后进入下次循环 就读入 下一个人的成绩
}

好耶!数据已经完美存进来了,接下来是将其排序,输出

实时排名显然先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。

所以是按以下条件排

  • AC题数

    • 当AC题数相等时,按时间排(用时越少排名越高)

      • 当时间也相等时,按名字字典序排

众所周知,显而易见,懂得都懂

冒泡排序的判断条件长这样

if(a[j - 1] < a[j])
{//....
}

很好!那么怎样在括号里多塞几个判断条件 而且 还是递进的判断呢

用 && || ! 肯定 8 行,这都是同时判断

那咋办嘛,只能用函数了

bool check(student &a, student &b) // 从后往前
{if(a.AC < b.AC) return true; // 如果b的AC数大于a的AC数就将他们交换位置else if (a.AC == b.AC){if(a.time > b.time) return true; // 同理交换else if(a.time == b.time){if(strcmp(a.name,b.name) > 0) return true; // 判断字典序,strcmp自己网上搜搜}}return false; // 如果三个 返回true的都没执行,那说明肯定 a 该排 b 前面
}

在判断中替换一下

if(check(stu[j - 1], stu[j])) // 如果函数返回true说明b该排在a前面
{student temp = stu[j - 1]; // 交换stu[j - 1] = stu[j];stu[j] = temp;
}

排序就不多说了,直接套模板

i--; // 注意while循环结尾时i会多++,减去1之后才是总人数
for(int q = 0; q <= i; q++)
{for(int j = i; j > q; j--){if(check(stu[j - 1], stu[j])) // 如果函数返回true说明b该排在a前面{student temp = stu[j - 1]; // 交换stu[j - 1] = stu[j];stu[j] = temp;}}
}

结束!排序完成,剩下一个输出

每个学生占一行,输出名字(10个字符宽),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。

字符宽的话就 %2d 就行,左右对齐则可以加 - + 号,比如 %-10s 左对齐输出10个字符宽的名字

printf("%-10s %2d %4d\n",stu[i].name,stu[i].AC,stu[i].time);

讲完!

5. 完整代码

#include <stdio.h>
#include <string.h> // 用 strcmp 需要
const int MAX = 100020;
struct student {int AC = 0;char name[11];int time = 0;
};
student stu[MAX];
​
bool check(student& a, student& b) // 从后往前
{if (a.AC < b.AC) return true; // 如果b的AC数大于a的AC数就将他们交换位置else if (a.AC == b.AC){if (a.time > b.time) return true; // 同理交换else if (a.time == b.time){if (strcmp(a.name, b.name) > 0) return true; // 判断字典序,strcmp自己网上搜搜}}return false; // 如果三个 返回true的都没执行,那说明肯定 a 该排 b 前面
}
​
int main()
{int n, m;scanf("%d%d", &n, &m);int i = 0;while (scanf("%s", &stu[i].name) != EOF && stu[i].name[0] != '0'){for (int j = 0; j < n; j++){int num;scanf("%d", &num);
​if (num <= 0)    continue;else stu[i].time += num;
​if (getchar() == '(')    // 处理括号{scanf("%d", &num);stu[i].time += num * m;getchar();}
​stu[i].AC++;}i++;}   i--; // 注意while循环结尾时i会多++,减去1之后才是最后一个人for (int q = 0; q <= i; q++) {for (int j = i ; j > q; j--){if (check(stu[j - 1], stu[j])) // 如果函数返回true说明b该排在a前面{student temp = stu[j - 1]; // 交换stu[j - 1] = stu[j];stu[j] = temp;}}}
​for (int j = 0; j <= i; j++)   // 输出{printf("%-10s %2d %4d\n", stu[j].name, stu[j].AC, stu[j].time);}return 0;
}

HDU 考试排名 题解 by Aze相关推荐

  1. HDU2093 考试排名

    考试排名 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  2. 2021贵州毕节高考成绩查询,2021贵州毕节选调生考试排名查询入口-时间(已开通)...

    2021贵州选调生笔试于3月27日结束,现在已进入4月27日,贵州毕节选调生考试排名已发布,为了让考生们了解毕节选调生考试成绩查询入口, 中公贵州选调生考试网为您整理于此,现整理相关入口如下,考生们可 ...

  3. 1339: 考试排名

    //几个月前做的,数据处理类型题目 1339: 考试排名 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 114 Solved: 34 [Submit][ ...

  4. 结构体排序二~1339: 考试排名(带技巧的输入)

    zcmu 1339: 考试排名 Time Limit: 1 Sec Memory Limit: 128 MB Description C++编程考试使用的实时提交系统,具有即时获得成绩排名的特点.它的 ...

  5. HDU2093 考试排名【排序】

    考试排名 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissi ...

  6. 计算机考试不在学籍库,有消息!中考报名将由学籍库直接导入,取消学校考试排名........

    原标题:有消息!中考报名将由学籍库直接导入,取消学校考试排名..... 最新中考日程 各初中校的中考均分,是家长在择校时的重要依据,甚至已经成为了唯一依据.而面对每年小升初时,如雪花般飞舞.名目繁多的 ...

  7. 向大佬学习C语言1198: 考试排名(二)(结构体专题)

    题目 1198: 考试排名(二)(结构体专题) 时间限制: 1 Sec 内存限制: 128 MB 提交: 3737 解决: 728ACM 国际大学生程序设计竞赛,英文全称:ACM Internatio ...

  8. 考试排名(结构体专题)

    考试排名(结构体专题) 题目描述 今天浙大研究生复试的上机考试跟传统笔试的打分规则相似,总共有n道题,每道题有对应分值,最后计算总成绩.现给定录取分数线,请你写程序找出最后通过分数线的考生,并将他们的 ...

  9. 1197: 考试排名(一)(结构体专题)

    1197: 考试排名(一)(结构体专题) 时间限制: 1 Sec  内存限制: 128 MB 提交: 59  解决: 70 [提交] [状态] [讨论版] [命题人:eilene] 题目描述 今天浙大 ...

最新文章

  1. Coursera课程Python for everyone:chapter5
  2. 常用损失函数(L1、L2、SSIM和MS-SSIM)对比简介
  3. 如何在eclipse中使用分支合并功能
  4. Java面向对象练习题之字母输出
  5. 常见电脑字符编码总结
  6. sql中排序序号_SQL 和 SPL 的有序运算对比
  7. easypoi list中的map导出_如何优雅的导出 Excel
  8. java 设置不可点击_Java Selenium webdriverwait 解决元素不可点击问题
  9. 18.Linux/Unix 系统编程手册(上) -- 目录与链接
  10. matlab之find函数
  11. 华为USG6000单臂路由
  12. html中设计对联,js实现很实用的对联广告代码 可自适应高度
  13. 手机输入法,谁能笑到最后?
  14. 计算机cpu天体图,电脑cpu天梯图2019|最新Intel/AMD处理器性能排行2019
  15. 线程main java中的异常怎么解决_线程“ main”中的异常java.lang.NoClassDefFoundError:...
  16. fig-tlo_PHP-FIG,Quo Vadis?
  17. 2018年阅读书物列表
  18. c语言口语评分系统,FCE口语评分标准:考官更喜欢这样的考生
  19. 无缝滚动--基本实现
  20. 【Python+C#】手把手搭建基于Hugging Face模型的离线翻译系统(如果你想,也可以在线)

热门文章

  1. 沿着“运营那条线”,新手要学哪些零散知识
  2. java中,子类初始化时一定要调用父类的构造方法,不调用行吗?
  3. 如何将美化过的sql转换为一行
  4. 查看git的远程主机名_git远程主机名是什么意思
  5. 全国首个超高层复合功能信息枢纽中心!深圳前海信息枢纽大厦!
  6. 一、【手机摄影】基础知识储备
  7. 【原版教材•中英对照】半导体器件物理——这本经典著作在半导体器件领域树立起了先进的学习和参考典范
  8. UI自动化_conftest.py 配置文件的作用
  9. 统计指定文件后缀的文件数量
  10. android中的EventLog