PTA 6-3评委打分-n,全网首发,含四个函数的分析,以及题目bug的纠正

心之所向,素履以往,终至所归

前言

今天学校发了几道题,而这道题罕见的在CSDN里找不到,同时题本身对刚学结构体的同学,也有一定难度所以想和大家分享一下我的一点心得。

1.题目信息

6-3 评委打分-n

分数 10

单位 武汉理工大学

题目描述

学校进行新生知识竞赛,最终n名同学进入决赛(n<=20)。为此,学生会邀请了7名德高望重的老教授与10名学生组成的大众评委一起作为评委。同时,也请学习了c语言的你帮忙编写一个程序,将评委给出的成绩,去掉一个最高分,去掉一个最低分后,计算出各位选手的最终得分,并按排名显示。
为方便提取每个学生信息,你设计了一个结构体类型Score,包含学生的编号(id)、姓名(name,不超过10个字符),并以一维数组value存储17名评委给出的成绩,同时将计算出的选手获得的最终成绩finalScore、比赛排名rank也作为成员记录到该结构体中,方便选手查询自己的名次。
定义一个一维数组grade存储10位学生成绩。
需要完成的函数功能为:

  1. GetScore(struct Score grade[], int n): 读入17个评委给出的n个学生成绩;

  2. CalcuScore(struct Score grade[], int n): 计算n个学生的最终成绩finalScore;

  3. Ranking(struct Score grade[], int n):依据最终成绩finalScore,计算出学生当前排名,赋给结构体成员rank;

  4. PrintScore(struct Score grade[], int n): 每行按照 “姓名 编号 第i名 最终成绩”的格式打印所有选手名次。每两部分之间一个空格,最终成绩按6列保留2位小数输出

自定义结构体类型

struct Score {  //成员包括学生编号、姓名、评分、总成绩、排名

};

函数接口定义:

void GetScore( struct Score grade[], int n );
void CalcuScore(struct Score grade[], int n);
void Ranking(struct Score grade[], int n);
void PrintScore(struct Score grade[], int n);

其中,grade[]n都是主调函数传入的参数。grade[]是结构体数组,n是选手人数,不超过20。

裁判测试程序样例:

#include<stdio.h>
struct Score {  //成员包括学生编号、姓名、评分、总成绩、排名

};

void GetScore( struct Score grade[], int n );
void CalcuScore(struct Score grade[], int n);
void Ranking(struct Score grade[], int n);
void PrintScore(struct Score grade[], int n);

int main()
{
    int n;
    scanf("%d", &n); //确定参加的选手人数
    struct Score grade[20];
    GetScore(grade, n);
    CalcuScore(grade, n);
    Ranking(grade, n);
    PrintScore(grade, n);
    return 0;
}

/* 请在这里填写答案 */

输入样例:

10
20001 Sandy  82  79  87  64  82  75  72  94  80  94  66  82  95  98  83  83  64
20002 Andy  95  65  83  95  93  65  72  86  66  75  84  73  85  74  84  60  68
20003 Kimmy  90  68  60  98  64  81  84  81  68  74  69 100  64  96  88  86  78
20004 Sussan  82  76  89  65  65  88  90  93  62  95  64  64  80  88  69  65  89
20005 Ryan  93  65  97  80  91  92  92  99  65  91  79  96 100  95  66  85  91
20006 Jone  74  67  68  94  84  86  91  86  63  62  71  96  92  68  74  96  63
20007 Tom   75  78  98  61 100  66  97  88  72  83  97  82  71  67  60  75  60
20008 Pokky  85  73  72  88  81  74  97  81  69  77  66  92  83  78  73  71  68
20009 Adolph  94  92  81  67  80  92  74  72  81  90  88  67  95  67  84  88  77
20010 Scolt  92  93  88  70  60  85  98  97  66  97  61  97  82  65  74  73  67

输出样例:

第1名 20005 Ryan  87.47
第2名 20009 Adolph  81.80
第3名 20001 Sandy  81.20
第4名 20010 Scolt  80.47
第5名 20003 Kimmy  79.27
第6名 20006 Jone  78.47
第7名 20007 Tom  78.00
第8名 20002 Andy  77.87
第9名 20004 Sussan  77.80
第10名 20008 Pokky  77.67

代码长度限制16 KB

时间限制400 ms

内存限制64 MB

2.bug分析

首先必须要说的一点是这道题本身就有bug!!!

请看第四个自定义函数要求:

我们再看样例;

很明显这两者的格式根本不一样!!!!!

而AC的条件则是以样例为准,方法也很简单只需要把样例复制粘贴过去然后把数值所在位置改为对应占位符即可,其实不止这到题,很多题也都最好这样,可以有效防止因为格式过不了。

3.

第一个:

循环输入即可,而且因为要输入17个人的评分,所以最好再嵌套一个循环

当然你想写17个占位符也是可以的,只是会看着有点冗长。

void GetScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)  //  每次输入一个同学的所有信息
    {
        scanf("%d %s", &grade[i].num, grade[i].name);
        for (int j = 0; j < 17; j++)       //此处是用于17个评委分数的输入
            scanf("%d", &grade[i].value[j]);
        getchar();
    }
}

第二个:

第二个函数是让你算每个人的平均得分,而且是弃掉一个最高分和一个最低分

那我们当然想到用排序,这里我用的是排序是双指针模式的快排,不了解的可以用冒泡,插入,选择等替代,总之就让17个评委打出的成绩排好顺序,(当然还有个原始方法,用一次循环找到最大最小值,同时也计算所有值的和,最后一减,)

void CalcuScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
    {
        grade[i].sum = 0;
        QuickSort(grade[i].value, 0, 16);
        for (int j = 1; j < 16; j++)
            grade[i].sum += grade[i].value[j];
        grade[i].sum /= 15;
    }
}

我是把快排又为封装了两个函数,如下;

void swap(int* a, int* b)
{
    int c = *a;
    *a = *b;           //用于交换数值
    *b = c;
}
void    QuickSort(int* arr, int begin, int end)   //快排的实现
{
    int front = begin + 1, behind = begin, key = begin;
    if (begin < end)
    {
        while (front <= end)
        {
            while (arr[front] > arr[key] && front <= end)
                front++;
            if (front <= end)
            {
                swap(&arr[front], &arr[behind + 1]);
                behind++;
                front++;
            }
        }
        swap(&arr[key], &arr[behind]);

        key = behind;
        QuickSort(arr, begin, key - 1);
        QuickSort(arr, key + 1, end);
    }
}

加油加油:快看完了

第二个函数的冒泡排序实现如下:

void CalcuScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < 16; j++)
        {
            int flag = 0;
            for (int z = 0; z < 16-j; z++)
            {
                double t;
                if (grade[i].value[z] > grade[i].value[z + 1])
                {
                    t = grade[i].value[z];
                    grade[i].value[z] = grade[i].value[z + 1];
                    grade[i].value[z + 1] = t;
                    flag = 1;
                }
            }
            if (flag == 0)
                break;
        }
    }
    for (int i = 0; i < n; i++)
    {
        double sum = 0;
        for (int j = 1; j < 16; j++)
            sum += grade[i].value[j];
        grade[i].finalScore = sum / 15;
    }
}

第三个:

第三个其实有个取巧的方法,你只需要把选手按照从成绩高到成绩低来排好序就OK了

如果是和我一个学校的那么请看看你们的这个题目集的6-1,以他为原型稍加改造就可是实现

这个我还是用的冒泡排序(不得不说,冒泡排序对新手真的很友好,真的建议都了解一下)。

void Ranking(struct Score* address, int N)
{
    for (int i = 0; i < N - 1; i++)
    {
        for (int j = 0; j < N - 1 - i; j++)
            if (address[j].sum- address[j + 1].sum< 0)
            {
                struct Score  a = address[j];
                address[j] = address[j + 1];
                address[j + 1] = a;
            }
    }
}

第四个:

记得吗我们要给选手们排出名次,题目本意是让我们在结构体中加个存储排名的变量,

but!!我们第三个函数已经给他们排好了顺序,所以只需要将它们一次打印出来就是答案,

至于排名,请看下图的“i+1”,没错!它就是排名,惊不惊喜?意不意外?

为什么是“i+1”不是“i”,别忘了,下标从零开始的。

void PrintScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)     //看“i+1”
       printf("第%d名 %d %s  %.2lf\n",i+1,grade[i].num,grade[i].name,grade[i].sum);
}

ok,至此四个函数大功告成啦,

恭喜你能坚持看完,一时半会理解不了也很正常,一个函数一个函数慢慢消化就好。

上答案;

struct Score {
    int num;
    char name[20];
    int value[20];
    double sum;
    int rank;
};
void Ranking(struct Score* address, int N)
{
    for (int i = 0; i < N - 1; i++)
    {
        for (int j = 0; j < N - 1 - i; j++)
            if (address[j].sum- address[j + 1].sum< 0)
            {
                struct Score  a = address[j];
                address[j] = address[j + 1];
                address[j + 1] = a;
            }
    }
}
void swap(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}
void    QuickSort(int* arr, int begin, int end)
{
    int front = begin + 1, behind = begin, key = begin;
    if (begin < end)
    {
        while (front <= end)
        {
            while (arr[front] > arr[key] && front <= end)
                front++;
            if (front <= end)
            {
                swap(&arr[front], &arr[behind + 1]);
                behind++;
                front++;
            }
        }
        swap(&arr[key], &arr[behind]);

        key = behind;
        QuickSort(arr, begin, key - 1);
        QuickSort(arr, key + 1, end);
    }
}
void GetScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
    {
        scanf("%d %s", &grade[i].num, grade[i].name);
        for (int j = 0; j < 17; j++)
            scanf("%d", &grade[i].value[j]);
        getchar();
    }
}
void CalcuScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
    {
        grade[i].sum = 0;
        QuickSort(grade[i].value, 0, 16);
        for (int j = 1; j < 16; j++)
            grade[i].sum += grade[i].value[j];
        grade[i].sum /= 15;
    }
}
void PrintScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
       printf("第%d名 %d %s  %.2lf\n",i+1,grade[i].num,grade[i].name,grade[i].sum);
}

还有一种比较中规中矩的,如下

struct Score {
    int id;
    char name[20];
    double value[17];
    double finalScore;
    int rank;// 成员包括学生编号、姓名、评分、总成绩、排名
};
void GetScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &grade[i].id);
        scanf("%s", grade[i].name);
        for (int j = 0; j < 17; j++)
            scanf("%lf", &grade[i].value[j]);
    }
}
void CalcuScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < 17; j++)
        {
            int flag = 0;
            for (int z = 0; z < 16; z++)
            {
                double t;
                if (grade[i].value[z] > grade[i].value[z + 1])
                {
                    t = grade[i].value[z];
                    grade[i].value[z] = grade[i].value[z + 1];
                    grade[i].value[z + 1] = t;
                    flag = 1;
                }
            }
            if (flag == 0)
                break;
        }
    }
    for (int i = 0; i < n; i++)
    {
        double sum = 0;
        for (int j = 1; j < 16; j++)
            sum += grade[i].value[j];
        grade[i].finalScore = sum / 15;
    }
}
void Ranking(struct Score grade[], int n)
{
    for (int i = n - 1; i >= 0; i--)
    {
        int flag = 0;
        for (int j = n - 1; j > n - 1 - i; j--)
        {
            struct Score t;
            if (grade[j].finalScore > grade[j - 1].finalScore)
            {
                t = grade[j];
                grade[j] = grade[j - 1];
                grade[j - 1] = t;
                flag = 1;
            }
        }
        if (flag == 0)
            break;
    }
    for (int i = 0; i < n; i++)
        grade[i].rank = i + 1;
}
void PrintScore(struct Score grade[], int n)
{
    for (int i = 0; i < n; i++)
        printf("第%d名 %d %s  %.2lf\n", grade[i].rank, grade[i].id, grade[i].name, grade[i].finalScore);
}

总结

我是一名非计科的编程爱好者,如果你也喜欢编程,那么与君共勉!

我之前也有一点基础知识的博客,想了解的同学可以看看哦

【如何正确使用外部变量和函数(文件包含与extern的使用) - CSDN App】http://t.csdnimg.cn/u8OsI

【while——do while——for 分支与循环的使用方法即注意事项(包括continue等关键字的使用) - CSDN App】http://t.csdnimg.cn/sh0Su

谢谢观看

觉得有用的话就点个免费的赞吧,

  • 92
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值