• 每日一题——奖学金


     哈喽大家好,我是保护小周ღ,本期为大家带来的是博主在牛客网上遇到的一道笔试题,题目不难,但是有点复杂(博主太菜了),博主在做题的过程中使用到了,结构体动态内存开辟数据排序,相关知识,包括写着写着被迫使用goto语句,还是值得学习一下的,有没有朋友有其他的解法,欢迎留言啊~

    目录

    博主题目分析:

    程序设计:

     程序实现:

    goto语句


    描述

    小v今年有n门课,每门都有考试,为了拿到奖学金,小v必须让自己的平均成绩至少为avg。每门课由平时成绩和考试成绩组成,满分为r。在考试前,小v他已经知道每门课的平时成绩为ai ,假设付出的时间与获得的分数成正比,若想让这门课的考试成绩多拿一分的话,小v要花bi 的时间复习,不复习的话当然就是0分。同时我们显然可以发现复习得再多也不会拿到超过满分的分数。问小v为了拿到奖学金,至少要花多少时间复习?

    输入描述:

    第一行三个整数n,r,avg(1 <= n <= 105,1 <= r <= 109,1 <= avg <= 106),接下来n行,每行两个整数ai和bi,(0 <= ai <= 106,1 <= bi <= 106) 注意:本题含有多组案例输入。

    输出描述:

    每个用例对应一行输出答案。

    示例1

    输入:

    5 10 9
    0 5
    9 1
    8 1
    0 1
    9 100
    3 5 3
    2 1
    4 100
    3 3
    

    输出:

    43
    0

    说明:

    示例1有两组测试用例。 对于第2组测试用例,小v的平时成绩的平均成绩为(2+4+3)/3=3分,已经达到拿奖学金的最低要求,所以可以不用复习。


    博主题目分析:

    1. 首先,小V想要拿奖学金,所以他必须保证,他的各科总平时成绩大于等于 avg ,每一门课的满分为 r ,然后 n 代表的是小V的所有学科。
    2. 第一轮输入 n=有多少门课,r=科目的满分是多少, avg=总平均成绩要达到avg,才能获得奖学金。
    3. 第二轮多组输入,输入 ai =该门课的平时成绩, 输入 bi =如果想要这门课的成绩提升一分,需要花多少时间复习。然后输入下一门课的ai 和bi;
    4. 复习得再多也不会拿到超过满分的分数。

    程序设计:

    题目要求使用多组输入,所以我们利用while()循环和scanf()函数的返回值,实现多组输入。

    第一次输入,n , r ,avg ;

    然后我们是不是应该定义一个数组,来记录小V同学的每门课的平时成绩,和如果想要这这些课的成绩提升一分,需要花多少时间复习。这两个种数据。

    定义什么?结构体类型的数组,因为同一门课的ai 和 bi 是有联系的,用结构体来描述,再适合不过。

    1. typedef struct student
    2. {
    3. int ai;//每门课的平时成绩
    4. int bi;//该门功课如果要涨分要花的时间
    5. }student;

    博主这个名字取得不太好,但是使用还是没有问题滴。

    小V有几门科目,咱们就开辟多大的空间,存储每一门的平均分数,和对应复习涨分所需要的时间

    1. student* xiaoV = (student*)malloc(sizeof(student) * n);
    2. if (xiaoV == NULL)//如果开辟失败就没必要继续了
    3. {
    4. perror("malloc");//报个错
    5. exit(-1);
    6. }

    第二轮循环输入 每门科目的 ai 和 bi ,此时呢,我们还应该记录一下这些科目的平时成绩之和。

    假如: 我们光靠平时成绩的平均分就>=avg,拿到奖学金,就不需要复习了。打印0即可。

    1. int sum = 0;//统计小V同学各科的平时成绩和
    2. for (int i = 0; i < n; ++i)
    3. {
    4. scanf("%d %d", &xiaoV[i].ai, &xiaoV[i].bi);
    5. sum += xiaoV[i].ai;
    6. }
    7. //如果小V同学的各科平时成绩就可以达到拿奖学金的程度。那就不用复习了
    8. if (sum / n >= avg)
    9. printf("0\n");

    否则:那就要复习了,题目要求:至少要花多少时间复习?

    所以,我们复习啊,必须要从涨分容易的科目开始,花的时间少,还能涨分,那我们优先要先找到那些涨分代价小的复习,然后记录一下复习花的时间,每涨一分,咱们就判断一下是否达到拿奖学金的程度,如果可以拿到奖学金,咱们就中止复习操作,然后输出花的时间即可。如果没有拿到,咱们就继续复习,涨分,判断,然后等该门课复习至满分后,继续复习下一门涨分代价小的复习重复操作。

    这个点主要的是找复习代价小的,通过什么判断呢,xiaoV[i].bi,小V需要花多少时间复习该门课涨一分。这个值越小越好啊,博主也没啥别的本事,排序耍的还行,我们直接将xiaoV的所以有科目按照xiaoV[i].bi,让xiaoV[i];从小到大排序,然后遍历,执行我上面说的操作。

    大家应该能够理解吧?理解的同学扣波1 ,咱们互动一下。


     程序实现:

    1. #include
    2. #include
    3. typedef struct student
    4. {
    5. int ai;//每门课的平时成绩
    6. int bi;//该门功课如果要涨分要花的时间
    7. }student;
    8. int main()
    9. {
    10. int n=0;//多少门功课
    11. int r=0;//满分
    12. int avg=0;//拿奖学金的平均分
    13. while(scanf("%d %d %d",&n,&r,&avg)!=EOF)
    14. {
    15. //小V有几门科目,咱们就开辟多大的空间,存储每一门的平均分数,和对应复习涨分所需要的时间
    16. student *xiaoV=(student*)malloc(sizeof(student)*n);
    17. if(xiaoV==NULL)//如果开辟失败就没必要继续了
    18. {
    19. perror("malloc");//报个错
    20. exit(-1);
    21. }
    22. int sum=0;//统计小V同学各科的平时成绩和
    23. for(int i=0;i
    24. {
    25. scanf("%d %d",&xiaoV[i].ai,&xiaoV[i].bi);
    26. sum+=xiaoV[i].ai;
    27. }
    28. //如果小V同学的各科平时成绩就可以达到拿奖学金的程度。那就不用复习了
    29. if(sum/n>=avg)
    30. printf("0\n");
    31. else
    32. {
    33. //冒泡排序,使涨分花时间代价小的排在前面,优先处理
    34. //当然也可以使用qsort()库函数排序
    35. for(int i=0;i
    36. {
    37. for(int j=0;j-1;++j)
    38. {
    39. if(xiaoV[j].bi>xiaoV[j+1].bi)//小的放在前面
    40. {
    41. student tmp=xiaoV[j];//定义结构体student类型的变量临时存储、交换
    42. xiaoV[j]=xiaoV[j+1];
    43. xiaoV[j+1]=tmp;
    44. }
    45. }
    46. }
    47. long time=0;//记录复习提分所需要的时间、因为输入案例较大所以使用long 型
    48. for(int i=0;i//判断某一门科目
    49. {
    50. //不会拿到超过满分的分数作为判断该科目能涨多少分的结束条件
    51. for(int j=xiaoV[i].ai+1; j<=r ;++j)//判断该门科目能涨多少分,并且记录所花的时间代价
    52. {
    53. time+=xiaoV[i].bi;//统计该科涨分的时间代价
    54. ++sum;//花时间复习就涨一分
    55. if(sum/n>=avg)//每涨一分我们就看看是否达到拿奖学金的最低分数
    56. {
    57. printf("%ld\n",time);
    58. free(xiaoV);//释放掉我们动态开辟的空间
    59. goto end;//我们使用goto跳转出循环
    60. }
    61. }
    62. }
    63. }
    64. end: ; //跳转至多组while循环的末尾,使其可以继续多组输入
    65. }
    66. return 0;
    67. }

    goto语句

    这里博主使用了goto 语句,关于goto 语句,博主简单讲两下:

    C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。 从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过 程。 例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。就像博主遇到的情况,已经达到可以拿到奖学金的程度,就没必要复习了。如果break;中止内部循环,实际上,外循环还是会继续运行的,没必要了。

    goto语言真正适合的场景如下: 

    for(...)  { 

          for(...)   {      

                 for(...)   {            

                                  if(disaster)  

                                  goto error;      

                 }  

          }    …

    }

    error: ;

     


    感兴趣的朋友可以用博主的方法,或者是自己的方法做做这道题,优化一下代码。

     题目来源于牛客网

    题目链接:奖学金_牛客题霸_牛客网 (nowcoder.com)

    本期收录于博主的专栏——每日一题,适用于编程初学者,有兴趣的朋友们可以订阅,查看其它“精彩小题”。每日一题_保护小周ღ的博客-CSDN博客

    感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ  *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

    ​​

      如有侵权请联系修改删除!

  • 相关阅读:
    [含毕业设计论文+PPT+源码等]ssm培训机构管理系统+Java后台管理系统|前后分离VUE
    vue考核点示例(仅供参考)
    .NET的CancellationTokenSource和ManualResetEvent结合使用
    vue:对三种获取更新后的dom的方式进行分析
    嵌入式实时操作系统的设计与开发(调度线程学习)
    git学习笔记——git pull篇
    【Java】认识类和对象
    QT 第六天 人脸识别系统
    VLAN实验一 VLAN的简单配置
    【数据库】Sql Server 2022通过临时表和游标遍历方式逻辑处理获取目标数据
  • 原文地址:https://blog.csdn.net/weixin_67603503/article/details/125979489