To evaluate the performance of our first year CS majored students, we consider their grades of three courses only: C - C Programming Language, M - Mathematics (Calculus or Linear Algebra), and E - English. At the mean time, we encourage students by emphasizing on their best ranks -- that is, among the four ranks with respect to the three courses and the average grade, we print the best rank for each student.
For example, The grades of C, M, E and A - Average of 4 students are given as the following:
StudentID C M E A
310101 98 85 88 90
310102 70 95 88 84
310103 82 87 94 88
310104 91 91 91 91
Then the best ranks for all the students are No.1 since the 1st one has done the best in C Programming Language, while the 2nd one in Mathematics, the 3rd one in English, and the last one in average.
Input
Each input file contains one test case. Each case starts with a line containing 2 numbers N and M (<=2000), which are the total number of students, and the number of students who would check their ranks, respectively. Then N lines follow, each contains a student ID which is a string of 6 digits, followed by the three integer grades (in the range of [0, 100]) of that student in the order of C, M and E. Then there are M lines, each containing a student ID.
Output
For each of the M students, print in one line the best rank for him/her, and the symbol of the corresponding rank, separated by a space.
The priorities of the ranking methods are ordered as A > C > M > E. Hence if there are two or more ways for a student to obtain the same best rank, output the one with the highest priority.
If a student is not on the grading list, simply output "N/A".
二、题意理解大意:每位同学有1个ID(6位数字构成)和4种分数(编程、数学、英语和平均分)。要求对每科单独进行排名。针对每一个查询ID,输出对应同学排名最高的那一科的科目名称及名次。
注意:若多门科目名次相同且最高,则按A>C>M>E的优先次序输出。
三、算法思想
1、创建两个结构体,一个记录同学ID和各科分数(用于排名),另一个记录同学ID和各科名次(用于散列表查找)。
注意:我们仅知道ID的特征是6位数字构成,即ID之间可能毫无规律可言,故它不能作为定位的指针。为了保证查询速度,我们采用散列表存储名次信息,因此在第二个结构体中也要记录ID,用于匹配查询目标。
2、针对结构体的排序,我们采用希尔-表排序算法。
3、每将一门科目排序完,都将排序结果加入到存储名次信息的散列表中。
四、C语言实现
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct{//同学ID和各科分数
int id;
float course[4];
}Students;
typedef struct rank{//同学ID、各科名次和指向下一个结构体的指针
int id;
int list[4];
struct rank* next;
}Ranks;
int N,M,T;
char sub[]={'A','C','M','E'};
void Read(Students* sds)//读取同学的各科分数
{
int i,j;
float total;
for(i=0;i<N;++i){
scanf("%d %f %f %f",&sds[i].id,&sds[i].course[1],&sds[i].course[2],&sds[i].course[3]);
total=0;//利用输出时A>C>M>E的优先次序,我们将course数组中0,1,2,3位置分别存储A,C,M,E的分数
for(j=1;j<4;++j)
total+=sds[i].course[j];
sds[i].course[0]=total/3;
}
}
void InitialSortArray(int *A)//重复利用表排序的临时数组
{
int i;
for(i=0;i<N;++i)
A[i]=i;
}
void ShellSort(int *A,int x,Students* sds)//希尔-表排序,
{//x表明当前对哪一科的成绩进行排序
int i,j,k,d,t;
for(k=log10(N+1)/log10(2);k>0;--k){
d=(int)pow(2,k)-1;
for(i=d;i<N;++i){
t=A[i];//数组A存储的是结构体数组sds中同学信息的索引
for(j=i;j>=d&&sds[t].course[x]>sds[A[j-d]].course[x];j-=d)
A[j]=A[j-d];
A[j]=t;
}
}
}
void Insert(int *A,int x,int n,int id,int loc,Ranks *rk)//将排序结果插入到名次信息散列表中
{//x表明当前插入的是哪一科的名次信息,n是名次,loc是根据ID计算出的在散列表中的映射位置
if(rk[loc].id==-1){//当前位置还未插入同学名次信息
rk[loc].id=id;
rk[loc].list[x]=n+1;
rk[loc].next=NULL;
}else{//发生冲突,用链表解决冲突问题
Ranks *p;
if(x==0){//插入第1科名次信息,即首次插入,故需要创建一个结构体
p=(Ranks*)malloc(sizeof(Ranks));
p->id=id;
p->list[x]=n+1;
p->next=(rk+loc)->next;
(rk+loc)->next=p;
}else{//插入第2...4科名次信息,此时同学的名次信息结构体已创建
p=rk+loc;
while(p&&p->id!=id)
p=p->next;
p->list[x]=n+1;
}
}
}
void InsertArray(int *A,int x,Students* sds,Ranks *rk)
{
int i,loc,cur=-1,n;
for(i=0;i<N;++i){
loc=sds[A[i]].id%T;//根据ID计算出在散列表中的映射位置
if(cur==-1||sds[A[i]].course[x]!=sds[A[i-1]].course[x]){//分数相同则名次相同,否则用实际排名
n=i;
cur=i;
}else
n=cur;
Insert(A,x,n,sds[A[i]].id,loc,rk);
}
}
void PrintArray(Ranks *rk)//输出最高名次及科目
{
int i,t=-1;
for(i=0;i<4;++i){
if(t==-1||rk->list[i]<rk->list[t])
t=i;
}
printf("%d %c\n",rk->list[t],sub[t]);
}
int main()
{
scanf("%d %d",&N,&M);
Students* sds=(Students*)malloc(N*sizeof(Students));
Read(sds);
int* sortarray=(int*)malloc(N*sizeof(int));
int i,id,loc;
T=N*2;//散列表大小为输入数据规模的2倍
Ranks* rk=(Ranks*)malloc(T*sizeof(Ranks));
for(i=0;i<T;++i)
rk[i].id=-1;//-1表示该位置未插入信息
for(i=0;i<4;++i){
InitialSortArray(sortarray);//表排序的临时数组进行初始化
ShellSort(sortarray,i,sds);//排序
InsertArray(sortarray,i,sds,rk);//往散列表中插入名次信息
}
for(i=0;i<M;++i){
scanf("%d",&id);
loc=id%T;
if(rk[loc].id==-1)
printf("N/A\n");
else{
Ranks* p=rk+loc;
while(p&&p->id!=id)
p=p->next;
if(!p)
printf("N/A\n");
else
PrintArray(p);
}
}
return 0;
}