※ PTA是 程序设计类实验辅助教学平台 ,里边包含一些编程题目集以供练习。
这道题用java解,我试了三种解法,不断优化,但始终是三个测试点通过、三个测试点超时。我把我的代码放在这里,做个参考吧。
题目
作者 CHEN, Li
单位 浙江大学
宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”
现给出一批考生的德才分数,请根据司马光的理论给出录取排名。
输入格式:
输入第一行给出 3 个正整数,分别为:N(≤10^5),即考生总数;L(≥60),为录取最低分数线,即德分和才分均不低于 L 的考生才有资格被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到但德分到优先录取线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于 H,但是德分不低于才分的考生属于“才德兼亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线 L 的考生也按总分排序,但排在第三类考生之后。
随后 N 行,每行给出一位考生的信息,包括:准考证号 德分 才分
,其中准考证号
为 8 位整数,德才分为区间 [0, 100] 内的整数。数字间以空格分隔。
输出格式:
输出第一行首先给出达到最低分数线的考生人数 M,随后 M 行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。
输入样例:
14 60 80
10000001 64 90
10000002 90 60
10000011 85 80
10000003 85 80
10000004 80 85
10000005 82 77
10000006 83 76
10000007 90 78
10000008 75 79
10000009 59 90
10000010 88 45
10000012 80 100
10000013 90 99
10000014 66 60
输出样例:
12
10000013 90 99
10000012 80 100
10000003 85 80
10000011 85 80
10000004 80 85
10000007 90 78
10000006 83 76
10000005 82 77
10000002 90 60
10000014 66 60
10000008 75 79
10000001 64 90
我用java写了三种解法,测试结果都是三个测试点正确、三个测试点超时。研究半天也没搞明白到底为什么超时(难道是只能用C语言才不会超时?),发出来做个参考吧。
用二维数组存储学生信息,同时用这个数组作为静态链表来排序(定义一个int作为头指针),最后打印时降序输出即可。代码如下。
/*
功能:根据规则对给定考生成绩进行排序并输出
实现思路:用数组存储每个考生的信息,并且用数组作为静态链表实现排序。
时间复杂度 空间复杂度
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] arr1 = br.readLine().split(" +");
int n = Integer.parseInt(arr1[0]); //考生总数
int l = Integer.parseInt(arr1[1]); //最低录取分数线
int h = Integer.parseInt(arr1[2]); //优秀录取线
//在线排序
int[][] a = new int[n][6]; //数组每一行代表一个考生,存储考号、德分、才分、总分、等级、链表序号
int m = 0; //录取总人数
String[] b = new String[3]; //接收当前考生的信息
int yi = -1; //已录取学生排序链表中的第一名的角标
for(int i=0;i=h && a[2]>=h){ //若德才均优秀
a[4] = 1; //第一类考生
return a;
}
if(a[1]>=h){ //若德分优秀而才分不优秀
a[4] = 2; //第二类考生
return a;
}
if(a[1]>=a[2]){ //若德分不优秀,但德分≥才分
a[4] = 3; //第三类考生
return a;
}
a[4] = 4; //其它考生为第四类考生
return a;
}
private static int[][] getSort(int[][] a,int t,int yi){
//功能:对数组中指定学生的成绩(以数组静态链表方式)排序并返回数组
//参数 a[][] 学生信息数组 ;t 待排序学生角标 ;yi 已排序的录取学生链表中第一名学生角标
if(yi==-1) //如果链表中还没有学生
return a; //则以待排序学生作为第一名,直接返回
if(gradeCompare(a[t],a[yi])){ //如果待排序的学生是新的第一名
a[t][5] = yi; //待排序学生链接指向原先的第一名
return a;
}
for(int i=yi,j=i;;i=a[i][5]){ //若链表中已经有至少一名学生,则正常进行排序
if(gradeCompare(a[i],a[t])){ //若待排序学生成绩<当前对比学生成绩
j=i; //用j记住当前对比学生角标
if(a[i][5]==-1){ //若当前对比学生已经是最后一名
a[i][5] = t; //将待排序学生插入到链表结尾
break; //排序完毕,退出循环
}
}
else{ //若待排序学生成绩>当前对比学生成绩
a[j][5] = t; //上一名的学生链接到待排序学生
a[t][5] = i; //待排序学生链接到当前对比学生
break; //排序完毕,退出循环
}
}
return a;
}
private static boolean gradeCompare(int[] a,int[] b){
//功能:比较两个学生成绩,学生a是否排名比学生b更靠前
if(a[4]b[4]) //若a比b等级更低
return false;
//若ab等级相同
if(a[3]>b[3]) //若总分a>b
return true;
if(a[3]b[1]) //若德分a>b
return true;
if(a[1]
有三个测试点超时,考虑到有可能是我自己写的排序算法太慢导致超时,于是我就又写了一个算法。
在接收学生信息时只存储不排序,打印时调用java的排序算法,在Arrays.sort()函数中传入一个Comparator匿名内部类(以便自定义排序规则)作为参数,实现排序,之后再降序打印输出。这个解法的一个缺点是要对包括未录取考生在内的所有考生进行排序,而解法一只对录取考生排序。解法二的测试结果仍然是有三个测试点超时。代码如下。
/*
功能:根据规则对给定考生成绩进行排序并输出
实现思路:用数组存储每个考生的信息,并在Arrays.sort()中传入一个Comparator匿名内部类作为参数,以实现排序。
时间复杂度 空间复杂度
*/
import java.io.*;
import java.util.*;
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] arr1 = br.readLine().split(" +");
int n = Integer.parseInt(arr1[0]); //考生总数
int l = Integer.parseInt(arr1[1]); //最低录取分数线
int h = Integer.parseInt(arr1[2]); //优秀录取线
//逐个接收考生信息
Integer[][] a = new Integer[n][5]; //数组每一行代表一个考生,存储考号、德分、才分、总分、等级
int m = 0; //录取总人数
String[] b = new String[3]; //接收当前考生的信息
for(int i=0;i() {
//new一个Comparator匿名内部类,重写compare方法
public int compare(Integer[] b, Integer[] a) {
if(a[4]b[4]) //若a比b等级更低
return -1;
//若ab等级相同
if(a[3]>b[3]) //若总分a>b
return 1;
if(a[3]b[1]) //若德分a>b
return 1;
if(a[1]=h && a[2]>=h){ //若德才均优秀
a[4] = 1; //第一类考生
return a;
}
if(a[1]>=h){ //若德分优秀而才分不优秀
a[4] = 2; //第二类考生
return a;
}
if(a[1]>=a[2]){ //若德分不优秀,但德分≥才分
a[4] = 3; //第三类考生
return a;
}
a[4] = 4; //其它考生为第四类考生
return a;
}
}
既然用java自带的排序算法也不行,那索性还是自己用数组做静态链表的排序吧。考虑到解法一中每个考生排序都要从第一类第一名开始比较,比较耗时,因此我又改进了一下,给四个类别分别设置一个本类别第一名的int角标作为指针。这样,每个考生在排序时只需从所属类别的第一名开始比较即可。此外,这个解法中我还把一些工具函数优化了一下。遗憾的是,测试结果仍然是三个点通过、三个点超时。
/*
功能:根据规则对给定考生成绩进行排序并输出
实现思路:用数组存储每个考生的信息,并且用数组作为静态链表实现排序。
时间复杂度 空间复杂度
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
//接收基本信息输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] arr1 = br.readLine().split(" +");
int n = Integer.parseInt(arr1[0]); //考生总数
int l = Integer.parseInt(arr1[1]); //最低录取分数线
int h = Integer.parseInt(arr1[2]); //优秀录取线
//数组初始化
int[][] a = new int[n][6]; //数组每一行代表一个考生,存储考号、德分、才分、总分、等级、链表序号
int m = 0; //录取总人数
String[] b = new String[3]; //接收当前考生的信息
Integer yi[] = new Integer[4]; //已录取学生排序链表中第一类至第四类的第一名的角标
for(int i=0;i<4;i++){ //数组初始化为-1
yi[i] = -1;
}
//在线处理 接收每个学生信息并排序存入数组中
for(int i=0,temp=-1;i=h){ //若德分优秀
a[4] = (a[2]>=h)?1:2; //若才分也优秀,则为第一类,否则为第二类
return a;
}
a[4] = (a[1]>=a[2])?3:4; //若德分不优秀,但德分≥才分,则为第三类,否则其它考生为第四类
return a;
}
private static int[][] getSort(int[][] a,int t,int yi){
//功能:对数组中指定学生的成绩(以数组静态链表方式)排序并返回数组
//参数 a[][] 学生信息数组 ;t 待排序学生角标 ;yi 待排序学生所属类别的第一名学生角标
if(yi==-1) //如果当前学生所属类别中还没有学生
return a; //则以待排序学生作为第一名,直接返回
if(gradeCompare(a[t],a[yi])){ //如果待排序的学生是新的第一名
a[t][5] = yi; //待排序学生链接指向原先的第一名
return a;
}
for(int i=yi,j=i;;i=a[i][5]){ //若链表中已经有至少一名学生,则正常进行排序
if(gradeCompare(a[i],a[t])){ //若待排序学生成绩<当前对比学生成绩
j=i; //用j记住当前对比学生角标
if(a[i][5]==-1){ //若当前对比学生已经是最后一名
a[i][5] = t; //将待排序学生插入到链表结尾
break; //排序完毕,退出循环
}
}
else{ //若待排序学生成绩>当前对比学生成绩
a[j][5] = t; //上一名的学生链接到待排序学生(此时j是链表中上一名学生的角标)
a[t][5] = i; //待排序学生链接到当前对比学生
break; //排序完毕,退出循环
}
}
return a;
}
private static boolean gradeCompare(int[] a,int[] b){
//功能:比较两个等级相等的学生成绩,学生a是否排名比学生b更靠前
if(a[3]!=b[3]) //若总分不相等
return (a[3]>b[3]); //则返回总分比较结果
if(a[1]!=b[1]) //若德分不相等
return (a[1]>b[1]); //则返回德分比较结果
return (a[0]
以上用java的三种解法都会超时,难道这道题必须用C语言才能不超时吗?也许可以根据考生成绩生成一个唯一的序号,再利用这个序号进行数组的快速排序?等试验了再回来更新吧。