PAT的等级列表是从状态列表中生成的,该列表显示提交的分数。这次您应该为PAT生成ranklist。
Input Specification:
每个输入文件包含一个测试用例。对于每种情况,第一行包含3个正整数N(≤104.),用户总数,K(≤5) ,问题总数,以及M(≤105.),即提交书的总数。然后假设用户id是从00001到N的5位数,问题id是从1到K。下一行包含K个正整数p[i](i=1,…,K),其中p[i]对应于第i个问题的满分。 接下来是M行,每行以以下格式给出提交的信息:
user_id problem_id partial_score_obtained
其中partial_ score_−1,或者是范围[0,p[problem_id]]内的整数。一行中的所有数字都用空格分隔。
Output Specification:
对于每个测试用例,您应该以以下格式输出ranklist:
rank user_id total_score s[1] ... s[K]
其中根据total_ score计算排名,具有相同total_;s[i]是针对第i个问题获得的部分分数。如果用户从未提交过问题的解决方案,则必须在相应位置打印“-”。如果用户提交了多个解决方案来解决一个问题,则将计算最高分数。
等级列表必须按等级的非递减顺序打印。对于排名相同的用户,必须根据完美解决问题的数量以非递增顺序对用户进行排序。如果仍然有领带,则必须按id的递增顺序打印。对于那些从未提交任何可通过编译器的解决方案或从未提交任何解决方案的人,他们不得显示在ranklist上。可以保证至少有一个用户可以显示在ranklist上。
Sample Input:
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
Sample Output:
1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 4 2
5 00004 40 15 0 25 -
注意:该题呢,要细节很重要,还要把题目好好捋清楚呢,一定要把题目好好读懂哦~
思路:
1. 首先呢,我们需要记好每个同学的数据,有总分数、完美解决问题个数、各个题目得分情况、id(在这里直接用数组下标表示即可)。所以我们需要定义一个结构体来把它们装成一个整体哦~
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int N,K,M;
int fullscore[6];//各题满分
struct node{
int grades[6];//题目数量最多是5道,而为了方便使序号从1开始,加个1,所以是6
int total;//总分
int perfect;//得全分的题数
};
2.然后,读入数据Readin()。
注意:1. 在初始化每个同学的每个题目的分数时,不能简单地初始化为-1,因为,输出时,如果该题未提交过,则输出‘ - ’;若提交过,但编译未过,得分为-1,但是输出分数是0(从测试用例可知),所以为区别该两种情况,可以考虑初始化为-2哦~
2. 在初始化Points[id].perfect时,
for(i=1;i<=M;i++){
scanf("%d%d%d",&id,&num,&score);
if(score>Points[id].grades[num]){
Points[id].grades[num]=score;
}
if(score==fullscore[num])
Points[id].perfect++;
}
该做法疏忽了一个点,要考虑如果多个满分同题程序提交的情况哦~
3. A同学没有提交过题目,而B同学提交过题目,但总得分为0 。我们知道A同学的total在初始化时也是0,所以要加以区分,令A同学的total值为-1即可区分开来呢~
完整Readin函数代码:
void Readin(struct node Points[]){
int i,j,flag;
int id,num,score;
//初始化
for(i=1;i<=K;i++)
scanf("%d",&fullscore[i]);
for(i=1;i<=N;i++){
for(j=1;j<=K;j++)
Points[i].grades[j]=-2;//代表未提交,而-1代表编译未过
Points[i].total=Points[i].perfect=0;
}
for(i=1;i<=M;i++){
scanf("%d%d%d",&id,&num,&score);
if(score>Points[id].grades[num]){
Points[id].grades[num]=score;
if(score==fullscore[num])//若满分程序多次提交,所以放在if里面
Points[id].perfect++;
}
}
//更新total
for(i=1;i<=N;i++){
flag=1;
for(j=1;j<=K;j++)
if(Points[i].grades[j]>=0){
flag=0;
Points[i].total+=Points[i].grades[j];
}
if(flag)Points[i].total=-1;//未提交过,不可出现在排名榜上
}
}
3. 然后就要依据总分进行排序啦,但是我们这一个节点就是一个结构体,如果按照普通排序的做法需要多次交换两节点的值,这可是要花费宝贵的时间呢呜,所以我们还是用表排序吧嘿嘿~(表排序在文末会简单地介绍一下的哦)
这里我用希尔排序加表排序哈~
int Compare(struct node sro[],int a,int b) {
//比较a和b,谁应该在前排,若返回1,说明a在前排;反之是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 {//都相同的话,就按id大小来排,小的在前排
if(a<b)
return 1;
else
return 0;
}
}
}
void Shell_Sort(struct node Points[],int table[]){
int i,j,k,d,t;
for(k=log(N+1)/log(2);k>0;k--){
d=pow(2,k)-1;
for(i=d+1;i<=N;i++){
t=table[i];
for(j=i;j>=d+1&&Compare(Points,t,table[j-d]);j=j-d)
table[j]=table[j-d];
table[j]=t;
}
}
}
如有疑惑,欢迎留言哦嘻嘻~
4. 最后就是输出啦~~~快结束啦哈哈哈~
void Print(struct node Points[],int table[]){
int i,j,cur;
for(i=1;i<=N;i++){
if(Points[table[i]].total<0)//表示该同学的总分都小于0了,排名在后面的一定也没救了,退出吧
break;
if(i==1||(i>=2&&Points[table[i]].total!=Points[table[i-1]].total)){
printf("%d %05d ",i,table[i]);//注意id输出格式呢~
cur=i;//记录最新排名,如果后面一位同学总分与之相同,则排名为cur
}
else printf("%d %05d ",cur,table[i]);
printf("%d ",Points[table[i]].total);
for(j=1;j<=K;j++){
if(Points[table[i]].grades[j]==-2)
printf("-");
else if(Points[table[i]].grades[j]==-1)
printf("0");
else printf("%d",Points[table[i]].grades[j]);
if(j!=K) printf(" ");//注意格式哦
else printf("\n");
}
}
}
完整代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int N,K,M;
int fullscore[6];//各题满分
struct node{
int grades[6];//题目数量最多是5道,而为了方便使序号从1开始,加个1,所以是6
int total;//总分
int perfect;//得全分的题数
};
void Readin(struct node Points[]){
int i,j,flag;
int id,num,score;
//初始化
for(i=1;i<=K;i++)
scanf("%d",&fullscore[i]);
for(i=1;i<=N;i++){
for(j=1;j<=K;j++)
Points[i].grades[j]=-2;//代表未提交,而-1代表编译未过
Points[i].total=Points[i].perfect=0;
}
for(i=1;i<=M;i++){
scanf("%d%d%d",&id,&num,&score);
if(score>Points[id].grades[num]){
Points[id].grades[num]=score;
if(score==fullscore[num])//若满分程序多次提交,所以放在if里面
Points[id].perfect++;
}
}
//更新total
for(i=1;i<=N;i++){
flag=1;
for(j=1;j<=K;j++)
if(Points[i].grades[j]>=0){
flag=0;
Points[i].total+=Points[i].grades[j];
}
if(flag)Points[i].total=-1;//未提交过,不可出现在排名榜上
}
}
int Compare(struct node sro[],int a,int b) {
//比较a和b,谁应该在前排,若返回1,说明a在前排;反之是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 {//都相同的话,就按id大小来排,小的在前排
if(a<b)
return 1;
else
return 0;
}
}
}
void Shell_Sort(struct node Points[],int table[]){
int i,j,k,d,t;
for(k=log(N+1)/log(2);k>0;k--){
d=pow(2,k)-1;
for(i=d+1;i<=N;i++){
t=table[i];
for(j=i;j>=d+1&&Compare(Points,t,table[j-d]);j=j-d)
table[j]=table[j-d];
table[j]=t;
}
}
}
void Print(struct node Points[],int table[]){
int i,j,cur;
for(i=1;i<=N;i++){
if(Points[table[i]].total<0)//表示该同学的总分都小于0了,排名在后面的一定也没救了,退出吧
break;
if(i==1||(i>=2&&Points[table[i]].total!=Points[table[i-1]].total)){
printf("%d %05d ",i,table[i]);//注意id输出格式呢~
cur=i;//记录最新排名,如果后面一位同学总分与之相同,则排名为cur
}
else printf("%d %05d ",cur,table[i]);
printf("%d ",Points[table[i]].total);
for(j=1;j<=K;j++){
if(Points[table[i]].grades[j]==-2)
printf("-");
else if(Points[table[i]].grades[j]==-1)
printf("0");
else printf("%d",Points[table[i]].grades[j]);
if(j!=K) printf(" ");//注意格式哦
else printf("\n");
}
}
}
int main(){
int i;
scanf("%d%d%d",&N,&K,&M);
struct node Points[N+1];
Readin(Points);
int table[N+1];
for(i=1;i<=N;i++){
table[i]=i;
}
Shell_Sort(Points,table);
Print(Points,table);
return 0;
}
附上俺的提交结果:
表排序:通过对key的比较来排序,但是我们不需要移动结构体,只需将结构体的下标放入table数组里面即可实现排序哈~
拜拜~