PAT1012
整体思路
这道题看下来就是比较简单的模拟题,穿插了对排序和查找的考察。
(1)存储:由于一个学生对象是有ID以及多个成绩信息,所以用自定义的结构体student来存储信息。多个学生就使用一个结构体数组stu来存储。
(2)排序:我们调用<algorithm>库中的sort函数,基本就是O(nlogn)的复杂度,自己写个描述排序规则的cmp函数即可。排序完,整个std数组就会按照我们的规则乖乖排好了,因为我们会有多次排序,所以每一次的排序结果都要记录下来,那这个时候每一次排序结果要存储在哪里??就是一个问题,这个问题也是这道题的一个难点,这直接关系到下一个步骤——查找的效率!!
好啦,想想我们是靠什么来查找的呢??是学生的ID号对吧,如果我们查找的时候能够按照ID号来对号入座,使用hash的方法,那时间复杂度就为O(n),即使在全部人都要一起来查找的情况下,算法也有很好的表现,对比起暴力查找方法O(n^2),简直就是人生赢家有木有(手动狗头)
(3)查找:如此一来,在解决完排序的存储方式问题后,查找就是很自然的事,直接就用ID去哈希一下就OK啦!
避坑指南
这道题还是有一丢丢的小坑的,不得不说细节还是很重要的,平时多练多总结,见得多的,练的熟了,自然避坑能力就会逐渐提高。
(1)排名的方式:12225(✔) 12223(❌)
(2)sort天坑:自己定义的cmp一定要使用 < 或者 > ,严格的大于小于,而不是<= ,>=,不然段错误就在前面等你,头铁定位了半天,检查各种循环边界条件和指针、数组索引,结果居然是你——一个 >= !!!气到呕血。。。 有机会的话,写一篇详细探究这个问题的博客。
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; //按照ACME顺序排列就不会有问题 struct student{ int id; int grade[4]; }stu[2010]; int now=0; /* 记忆方法:sort实现升序排序,cmp函数的意义就是结果为真,放到前面 */ bool cmp(student s1,student s2){ //升序降序真的是个混乱的坑,得想办法搞好 return s1.grade[now] > s2.grade[now]; //!!!写成>=会造成段错误 } int rank_map[1000000][4]; //模拟哈希 int main() { freopen("in.txt","r",stdin); memset(rank_map,0,sizeof(rank_map)); int stu_num; int che_num; scanf("%d %d",&stu_num,&che_num); for(int i=0;i<stu_num;++i){ scanf("%d %d %d %d",&stu[i].id,&stu[i].grade[1],&stu[i].grade[2],&stu[i].grade[3]); stu[i].grade[0]=(stu[i].grade[1]+stu[i].grade[2]+stu[i].grade[3])/3; } for(now=0;now<4;++now){ sort(stu,stu+stu_num,cmp); //排序 //存储 int r=1; rank_map[stu[0].id][now]=r; for(int j=1;j<stu_num;++j){ //如果stu_num==0,是不是!=stu_num会死循环 if(stu[j].grade[now]!=stu[j-1].grade[now]) r=j+1; rank_map[stu[j].id][now]=r; } } //查找 char c[5]={'A','C','M','E'}; int check; for(int i=0;i!=che_num;++i){ scanf("%d",&check); if(i!=0) printf("\n"); if(rank_map[check][0]==0) printf("N/A"); else { int min=0; int min_num=rank_map[check][0]; for(int j=1;j<4;++j){ if(rank_map[check][j]<min_num){ min=j; min_num=rank_map[check][j]; } } printf("%d %c",min_num,c[min]); } } return 0; }