HDU 考试排名 题解 by Aze
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相关推荐
- HDU2093 考试排名
考试排名 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- 2021贵州毕节高考成绩查询,2021贵州毕节选调生考试排名查询入口-时间(已开通)...
2021贵州选调生笔试于3月27日结束,现在已进入4月27日,贵州毕节选调生考试排名已发布,为了让考生们了解毕节选调生考试成绩查询入口, 中公贵州选调生考试网为您整理于此,现整理相关入口如下,考生们可 ...
- 1339: 考试排名
//几个月前做的,数据处理类型题目 1339: 考试排名 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 114 Solved: 34 [Submit][ ...
- 结构体排序二~1339: 考试排名(带技巧的输入)
zcmu 1339: 考试排名 Time Limit: 1 Sec Memory Limit: 128 MB Description C++编程考试使用的实时提交系统,具有即时获得成绩排名的特点.它的 ...
- HDU2093 考试排名【排序】
考试排名 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissi ...
- 计算机考试不在学籍库,有消息!中考报名将由学籍库直接导入,取消学校考试排名........
原标题:有消息!中考报名将由学籍库直接导入,取消学校考试排名..... 最新中考日程 各初中校的中考均分,是家长在择校时的重要依据,甚至已经成为了唯一依据.而面对每年小升初时,如雪花般飞舞.名目繁多的 ...
- 向大佬学习C语言1198: 考试排名(二)(结构体专题)
题目 1198: 考试排名(二)(结构体专题) 时间限制: 1 Sec 内存限制: 128 MB 提交: 3737 解决: 728ACM 国际大学生程序设计竞赛,英文全称:ACM Internatio ...
- 考试排名(结构体专题)
考试排名(结构体专题) 题目描述 今天浙大研究生复试的上机考试跟传统笔试的打分规则相似,总共有n道题,每道题有对应分值,最后计算总成绩.现给定录取分数线,请你写程序找出最后通过分数线的考生,并将他们的 ...
- 1197: 考试排名(一)(结构体专题)
1197: 考试排名(一)(结构体专题) 时间限制: 1 Sec 内存限制: 128 MB 提交: 59 解决: 70 [提交] [状态] [讨论版] [命题人:eilene] 题目描述 今天浙大 ...
最新文章
- Coursera课程Python for everyone:chapter5
- 常用损失函数(L1、L2、SSIM和MS-SSIM)对比简介
- 如何在eclipse中使用分支合并功能
- Java面向对象练习题之字母输出
- 常见电脑字符编码总结
- sql中排序序号_SQL 和 SPL 的有序运算对比
- easypoi list中的map导出_如何优雅的导出 Excel
- java 设置不可点击_Java Selenium webdriverwait 解决元素不可点击问题
- 18.Linux/Unix 系统编程手册(上) -- 目录与链接
- matlab之find函数
- 华为USG6000单臂路由
- html中设计对联,js实现很实用的对联广告代码 可自适应高度
- 手机输入法,谁能笑到最后?
- 计算机cpu天体图,电脑cpu天梯图2019|最新Intel/AMD处理器性能排行2019
- 线程main java中的异常怎么解决_线程“ main”中的异常java.lang.NoClassDefFoundError:...
- fig-tlo_PHP-FIG,Quo Vadis?
- 2018年阅读书物列表
- c语言口语评分系统,FCE口语评分标准:考官更喜欢这样的考生
- 无缝滚动--基本实现
- 【Python+C#】手把手搭建基于Hugging Face模型的离线翻译系统(如果你想,也可以在线)