1015 德才论

我们是 冠军!

一开始报段错误

后来报超时

最后报错

这道题属实是给我折磨完了

先贴代码,最后总结

1015 德才论 (25 分)

宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”

现给出一批考生的德才分数,请根据司马光的理论给出录取排名。

输入格式:

输入第一行给出 3 个正整数,分别为:N(≤105),即考生总数;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

题解:

#include<stdio.h>
typedef struct student
{
	long long num;
	int d;
	int c;
}stu;

void print(stu* s)
{
	for (int i = 0; s[i].num != 0; i++)
	{
		printf("%d %d %d\n", s[i].num, s[i].d, s[i].c);
	}
}

int cmp(const void* a, const void* b)
{
	stu* c = (stu*)a;
	stu* d = (stu*)b;
	int sum1 = c->c + c->d;
	int sum2 = d->c + d->d;
	if (sum1 != sum2)
	{
		return sum2 - sum1;
	}
	else if (c->d != d->d)
	{
		return d->d - c->d;
	}

	else return c->num - d->num;
}

int main()
{
	int out1 = 0, out2 = 0, out3 = 0, out4 = 0;
	int sum;
	int L;
	int H;//优先录取线
	scanf("%d %d %d", &sum, &L, &H);
	static stu student[100000];
	static stu student1[100000] = { 0 };
	static stu student2[100000] = { 0 };
	static stu student3[100000] = { 0 };
	static stu student4[100000] = { 0 };

	for (int i = 0; i < sum; i++)
	{
		scanf("%d", &student[i].num);
		scanf("%d", &student[i].d);
		scanf("%d", &student[i].c);
	}

	for (int i = 0; i < sum; i++)
	{
		if (student[i].d >= H && student[i].c >= H)
		{
			student1[out1] = student[i];
			out1++;
		}
		else if (student[i].d >= H && student[i].c < H && student[i].c >= L)
		{
			student2[out2] = student[i];
			out2++;
		}
		else if (student[i].d < H && student[i].c < H && student[i].d >= student[i].c && student[i].d >= L && student[i].c >= L)
		{
			student3[out3] = student[i];
			out3++;
		}
		else if (student[i].d >= L && student[i].c >= L)
		{
			student4[out4] = student[i];
			out4++;
		}
	}
	
	//快速排序
	
	qsort(student1, out1, sizeof(stu), cmp);
	qsort(student2, out2, sizeof(stu), cmp);
	qsort(student3, out3, sizeof(stu), cmp);
	qsort(student4, out4, sizeof(stu), cmp);

	printf("%d\n", out1 + out2 + out3 + out4);
	print(student1);
	print(student2);
	print(student3);
	print(student4);
}

总结:

下面依次总结所有问题:

  1. 段错误。显然是数组的越界问题,但是题目要求就是100000,没办法啊,答案是在VS中,使用static设置为全局变量,内存就够了。

  2. 超时。可以优化的地方太多了,而且我现在的写法依旧有优化的空间

    1.先说大问题,一开始我是手写的冒泡排序,每读取一个就插入一个,时间复杂度n^2,虽然很清楚明了,但是显然是可以优化成nlogn的。而c语言中有自带的快速排序函数qsort(),在此我没有深入研究,因为数据结构还没看到那里呢,总之就是可以优化。

    2.刚开始改成快速排序,由于还是要把数据分为四大类,我还是每次遍历数组直到数据不为空,然后插入新的数据。我寻思数组的优势不就是随机读写吗,只需要每次插入后计数,就可以每次精准的插到最后。之前每次遍历都需要一个o(n),现在直接优化成o(1)了。

    3.这点可忽略,之前冒泡排序的时候每次还遍历一次数组求长度,属于是逆天

  3. 答案错误。优化了半天,终于不超时,改几把报错了。

    问题很简单,构造cmp函数时,搞错了总分相等时的情况,改下就好了。

可以优化的地方还很多,但我还要tm背英语,就这样了,这题属于是收获颇多了!

参考文章

static数组 https://blog.csdn.net/weixin_34923852/article/details/117116675
代码和我类似,这兄弟也是参考的别人的,我属于三手代码 https://blog.csdn.net/YelloJesse/article/details/82377704
还有个兄弟提醒我不用每次遍历,直接计数插入就可以了,找不到了
posted @ 2022-04-01 21:50  huigugu  阅读(49)  评论(0编辑  收藏  举报