本博文源于浙江大学《数据结构》,今天跟随姥姥做习题,发现此题是真的繁琐,比统计工龄繁杂n倍(统计工龄我已附上链接),不过再难也要理出头绪,下面给出具体的细节分析
(c语言详解)10-排序4 统计工龄(简洁版详细解释)
原文(翻译)如下:
PAT的ranklist是由状态列表生成的,其中显示了提交的分数。这一次,您应该为PAT生成ranklist。
输入规格:
每个输入文件包含一个测试用例。对于每种情况,第一行包含3个正整数,N(≤104),用户总数,K(≤5),问题总数,M(≤10^5),以及提交作品的总数。然后假设用户id是从00001到N的5位数字,而问题id是从1到K的。下一行包含K个正整数p[i] (i=1,…,其中p[i]对应第i个问题的满分。接下来是M行,每一行都给出了一个提交的信息,格式如下:
user_id problem_id partial_score_obtained
其中partial_score_为- 1(如果提交甚至不能通过编译器),或者为[0,p[problem_id]]范围内的整数。一行中的所有数字都用空格隔开。
输出规范:
对于每个测试用例,您应该按照以下格式输出ranklist:
user_id total_score s[1]…s [K]
其中根据total_score计算rank,具有相同total_score的所有用户获得相同的rank;s[i]是第i个问题得到的部分分数。如果用户从未提交过问题的解决方案,则必须在相应位置打印“-”。如果用户为解决一个问题提交了多个解决方案,那么将计算最高分。
ranklist必须按秩的非递减顺序打印。对于具有相同级别的用户,必须根据完美解决的问题的数量按非递增顺序排序。如果仍然有领带,则必须按其id的递增顺序打印。对于那些从来没有提交过任何可以通过编译器的解决方案的人,或者从来没有提交过任何解决方案的人,他们不能显示在ranklist上。可以保证至少有一个用户可以显示在ranklist上。
样例输入:
7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0
样例输出:
1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 42
5 00004 40 15 0 25 -
分析输入输出
输入第一行
第一个参数 用户的个数
第二个参数 问题的个数
第三个参数 记录的个数
输入第二行
四个问题的分别总分
输入第三行起
第一个参数用户id,第几个问题 该用户的得分
其中-1表示未编译通过,0表示编程错误有分
输出
第一个参数名次
第二个参数 用户编号
第三个参数 用户四道题目总分
第四个参数起各个题目用户的相应得分
破题关键
为用户建立结构体,结构体存储用户信息,然后根据读取,为用户信息进行更新,最后来个表排序,最后按照格式输出用户信息即可。看起来我说的非常顺畅那么怎么实现呢?
read函数
主要将信息读入,这个函数任务先做简单的初始化,比如未提交,用户存在但没分数的你做最后比较如何标记,你都可以在初始化帮他们设定,比如我,未曾回答设个值,如果回答了,直接将值跟新。还有你每次提交是不是要跟新这个值,最后为他们统计个总分,这全部都可以在read函数实现
compare函数
给分数做排序有个关键是为总分排序,而不是为每道题目排序,因此这个compare函数是定义排序规则,在这里排序的规则是总分咯,设定一下
ShellSort函数
希尔排序或者其他排序都行,最主要的把compare函数调用进去,在这里未实现copy,而是做了简单的表排序,如果大家表排序不知道,可以看这篇博主写的文章
(C语言浙大版)小白实现表排序含基本原理(附测试用例)
仅作非物理排序,这是最简单的。况且希尔排序的增量序列,也仅仅是选择排序的升级版本。
main函数
读入第一行得数据,开始准备活动做好,然后调用相应的函数,先read函数调用好,然后调用排序函数,最后为了格式安全,输出用户信息,然后开始提交。
附上源码
//px-1-2.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct {
int eachpro[6];
int total;
int perfect;
}Score;
int N,K,M;
int fullmark[6];
void Read(Score * sro)
{
int i,j,id,num,mark,flag;
for(i=0;i<N;++i) {
for(j=1;j<=K;++j)
sro[i].eachpro[j] = -2; //表示未曾回答,-1为通过
sro[i].total = 0;
sro[i].perfect = 0;
}
for(i=0;i<M;++i) {
scanf("%d %d %d",&id,&num,&mark);
if(sro[id-1].eachpro[num]<mark)
sro[id-1].eachpro[num] = mark;
}
for(i=0;i<N;++i) {
flag = 1;
for(j=1;j<=K;++j) {
if(sro[i].eachpro[j]>=0) {
flag = 0;
sro[i].total += sro[i].eachpro[j];
if(sro[i].eachpro[j] == fullmark[j])
sro[i].perfect++;
}
}
if(flag)
sro[i].total = -1;
}
}
int Compare(Score *sro,int a,int b) {
if(sro[a].total > sro[b].total)
return 1;
else if(sro[a].total<sro[b].total)
return 0;
else {
if(sro[a].perfect>sro[b].perfect)
return 1;
else if(sro[a].perfect<sro[b].perfect)
return 0;
else {
if(a<b)
return 1;
else
return 0;
}
}
}
void ShellSort(Score *sro,int *index) {
int i,j,k,d,t;
for(k=log10(N+1)/log10(2);k>0;--k) {
d = pow(2,k)-1;
for(i=d;i<N;++i) {
t = index[i];
for(j=i;j>=d&&Compare(sro,t,index[j-d]);j-=d)
index[j] = index[j-d];
index[j] = t;
}
}
}
int main()
{
scanf("%d %d %d",&N,&K,&M);
int i;
for(i=1;i<=K;++i)
scanf("%d",&fullmark[i]);
Score* sro=(Score*)malloc(N*sizeof(Score));
Read(sro);
int* index=(int*)malloc(N*sizeof(int));
for(i=0;i<N;++i)
index[i]=i;
ShellSort(sro,index);
int cur,j;
for(i=0;i<N;++i){//输出结果
if(sro[index[i]].total==-1)
break;
if(!i||(i>0&&sro[index[i]].total!=sro[index[i-1]].total)){//与前一用户的总分不同,则按实际排名输出
printf("%d ",i+1);
cur=i+1;//最新用户排名
}else
printf("%d ",cur);//与前一用户总分相同,则按前一用户的排名输出
printf("%05d ",index[i]+1);
printf("%d ",sro[index[i]].total);
for(j=1;j<=K;++j){
if(sro[index[i]].eachpro[j]==-2)//未被回答过
printf("-");
else if(sro[index[i]].eachpro[j]==-1)//未通过编译
printf("0");
else
printf("%d",sro[index[i]].eachpro[j]);
if(j!=K)
printf(" ");
else
printf("\n");
}
}
return 0;
}