PTA 数据结构与算法 7-41 PAT排名汇总

如有不对,不吝赐教
进入正题:
计算机程序设计能力考试(Programming Ability Test,简称PAT)旨在通过统一组织的在线考试及自动评测方法客观地评判考生的算法设计与程序设计实现能力,科学的评价计算机程序设计人才,为企业选拔人才提供参考标准(网址http://www.patest.cn)。

每次考试会在若干个不同的考点同时举行,每个考点用局域网,产生本考点的成绩。考试结束后,各个考点的成绩将即刻汇总成一张总的排名表。

现在就请你写一个程序自动归并各个考点的成绩并生成总排名表。

输入格式:
输入的第一行给出一个正整数N(≤100),代表考点总数。随后给出N个考点的成绩,格式为:首先一行给出正整数K(≤300),代表该考点的考生总数;随后K行,每行给出1个考生的信息,包括考号(由13位整数字组成)和得分(为[0,100]区间内的整数),中间用空格分隔。

输出格式:
首先在第一行里输出考生总数。随后输出汇总的排名表,每个考生的信息占一行,顺序为:考号、最终排名、考点编号、在该考点的排名。其中考点按输入给出的顺序从1到N编号。考生的输出须按最终排名的非递减顺序输出,获得相同分数的考生应有相同名次,并按考号的递增顺序输出。

输入样例:
2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

输出样例:
9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

这道题目搞了半天还是为了排序,但是这里有一个问题就是排序不仅仅是有每个考点的排序,还有所有考点综合在一起的排序,就有点像桶排序。我选择分考点快排,所有考点在分考点快排完后建立一个容量为N的小顶堆,进行堆排序。
下面给出代码:

#include<stdio.h>
#include<string.h>
#include<malloc.h>

struct Examinee{
char testNumber[14];  //考生号
int score;           //成绩
};                   //考生信息

struct TestPoint{
int people;    //考点总人数
int cur;       //最后总人数排序时该考点的当前排到的人的位置
int rank;      //当前排到的人的排名
int gap;          //用于记录同分的人
struct Examinee *testPeople;    //考点的考生
};

struct HeapNode{
int score;
int pointNum;      //考点号
int pointRank;     //考生在考点的名次
char testNumber[14];
};

int tail=0;

void QuickSort(struct Examinee *testPeople,int left,int right);
struct HeapNode GetHeap(struct HeapNode *heap);
void Insert(struct HeapNode *heap,struct TestPoint *point,int pointNum);
void Free(struct TestPoint *point,int N);

int main(void)
{
    int N,K,all=0;     //all为总的考生人数
    int i,j;
    int rank=1;          //最终所有人的排名
    int gap;               //计算排名用到
    scanf("%d",&N);    //考点人数
    struct TestPoint point[N];   //N个考点
    struct HeapNode heap[N];     //N个元素的大顶堆
    struct HeapNode result;      //用于输出结果

    for(i=0;i<N;i++){
      scanf("%d",&K);      //该考点人数
      if(!K)
        continue;
      point[i].people=K;
      point[i].cur=0;         //初始化考点的信息
      point[i].rank=1;
      point[i].gap=1;
      point[i].testPeople=(struct Examinee *)malloc(K*sizeof(struct Examinee));  //分配空间

      for(j=0;j<K;j++){
        scanf("%s",point[i].testPeople[j].testNumber);  //获取考号
        scanf("%d",&point[i].testPeople[j].score);      //获取成绩
      }
      QuickSort(point[i].testPeople,0,K-1);     //按照成绩先快速排序一遍
      all+=K;        //计算总人数
    }        //处理输入数据

    for(i=0;i<N;i++){
      Insert(heap,point+i,i);
    }                      //先初始化堆

    printf("%d\n",all);
    for(i=0,gap=1;i<all;i++){
      result=GetHeap(heap);
      printf("%s %d ",result.testNumber,rank);
      printf("%d %d\n",result.pointNum+1,result.pointRank);
      if(point[result.pointNum].cur!=point[result.pointNum].people)
        Insert(heap,point+result.pointNum,result.pointNum);        //只有该考点还有人
      if(result.score!=heap[0].score){
        rank+=gap;    //只有和新的最大节点的成绩不等是总排名才增加
        gap=1;
      }
      else
        gap++;
    }

    Free(point,N);

    return 0;
}

void QuickSort(struct Examinee *testPeople,int left,int right)
{
    if(left>=right)
      return ;

    int i=left;
    int j=right;
    struct Examinee temp;

    while(i<j){
      while(testPeople[j].score<=testPeople[left].score&&i<j)
        if((testPeople[j].score<testPeople[left].score)||(testPeople[j].score==testPeople[left].score&&strcmp(testPeople[j].testNumber,testPeople[left].testNumber)>0))
          j--;
        else
          break;

      while(testPeople[i].score>=testPeople[left].score&&i<j)
        if((testPeople[i].score>testPeople[left].score)||(testPeople[i].score==testPeople[left].score&&strcmp(testPeople[i].testNumber,testPeople[left].testNumber)<0)||i==left)
          i++;
        else
          break;

      if(i<j){
        temp=testPeople[i];
        testPeople[i]=testPeople[j];
        testPeople[j]=temp;
      }
    }

    temp=testPeople[left];
    testPeople[left]=testPeople[i];
    testPeople[i]=temp;

    QuickSort(testPeople,left,i-1);
    QuickSort(testPeople,i+1,right);

    return ;
}

void Insert(struct HeapNode *heap,struct TestPoint *point,int pointNum)
{
    int son,father;
    struct HeapNode temp;

    heap[tail].score=point->testPeople[point->cur].score;
    strcpy(heap[tail].testNumber,point->testPeople[point->cur].testNumber);
    heap[tail].pointRank=point->rank;    //填入数据
    heap[tail].pointNum=pointNum;        //考点号
    if(point->testPeople[point->cur].score!=point->testPeople[point->cur+1].score){
      point->rank+=point->gap;  //只有在前后两个人的成绩不相同的时候排名才会变化
      point->gap=1;
    }
    else
      point->gap++;     //同分的人数
    point->cur++;             //已排序过的人数加一

    son=tail;
    tail++;
    father=(son+(son&1))/2-1;

    if(!son)
      return ;

    while(heap[son].score>=heap[father].score&&father>=0){
      if((heap[son].score>heap[father].score)||(heap[son].score==heap[father].score&&strcmp(heap[son].testNumber,heap[father].testNumber)<0)){
        temp=heap[son];
        heap[son]=heap[father];
        heap[father]=temp;          //交换父子两节点位置
      }
      son=father;
      father=(father+(father&1))/2-1;
    }

    return ;
}

struct HeapNode GetHeap(struct HeapNode *heap)
{
    struct HeapNode result=heap[0];
    struct HeapNode temp;     //交换父子节点的中间变量
    int father=0;
    int son=1;

    if(tail>=1)
      heap[0]=heap[--tail];

    while(son<tail){
      if(heap[son].score<=heap[son+1].score&&son+1<tail)
        if(heap[son].score<heap[son+1].score||(heap[son].score==heap[son+1].score&&strcmp(heap[son].testNumber,heap[son+1].testNumber)>0))
        son++;                      //找到孩子节点中成绩最好的节点
      if(heap[father].score<=heap[son].score){
        if((heap[son].score>heap[father].score)||(heap[son].score==heap[father].score&&strcmp(heap[son].testNumber,heap[father].testNumber)<0)){
          temp=heap[father];
          heap[father]=heap[son];
          heap[son]=temp;            //交换父子节点
        }
        father=son;
        son=2*son+1;
      }
      else
        break;
    }

    return result;
}

void Free(struct TestPoint *point,int N) //考点 考点总数
{
    int i;

    for(i=0;i<N;i++){
      if(point[i].testPeople)
        free(point[i].testPeople);
      point[i].testPeople=NULL;
    }

    return ;
}

测试结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值