编辑
哈喽大家好,我是保护小周ღ,本期为大家带来的是博主在牛客网上遇到的一道笔试题,题目不难,但是有点复杂(博主太菜了),博主在做题的过程中使用到了,结构体,动态内存开辟,数据排序,相关知识,包括写着写着被迫使用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分,已经达到拿奖学金的最低要求,所以可以不用复习。
博主题目分析:
- 首先,小V想要拿奖学金,所以他必须保证,他的各科总平时成绩大于等于 avg ,每一门课的满分为 r ,然后 n 代表的是小V的所有学科。
- 第一轮输入 n=有多少门课,r=科目的满分是多少, avg=总平均成绩要达到avg,才能获得奖学金。
- 第二轮多组输入,输入 ai =该门课的平时成绩, 输入 bi =如果想要这门课的成绩提升一分,需要花多少时间复习。然后输入下一门课的ai 和bi;
- 复习得再多也不会拿到超过满分的分数。
程序设计:
题目要求使用多组输入,所以我们利用while()循环和scanf()函数的返回值,实现多组输入。
第一次输入,n , r ,avg ;
然后我们是不是应该定义一个数组,来记录小V同学的每门课的平时成绩,和如果想要这这些课的成绩提升一分,需要花多少时间复习。这两个种数据。
定义什么?结构体类型的数组,因为同一门课的ai 和 bi 是有联系的,用结构体来描述,再适合不过。
typedefstructstudent{ intai;//每门课的平时成绩intbi;//该门功课如果要涨分要花的时间}student;
博主这个名字取得不太好,但是使用还是没有问题滴。
小V有几门科目,咱们就开辟多大的空间,存储每一门的平均分数,和对应复习涨分所需要的时间
student*xiaoV= (student*)malloc(sizeof(student) *n); if (xiaoV==NULL)//如果开辟失败就没必要继续了{ perror("malloc");//报个错exit(-1); }
第二轮循环输入 每门科目的 ai 和 bi ,此时呢,我们还应该记录一下这些科目的平时成绩之和。
假如: 我们光靠平时成绩的平均分就>=avg,拿到奖学金,就不需要复习了。打印0即可。
intsum=0;//统计小V同学各科的平时成绩和for (inti=0; i<n; ++i) { scanf("%d %d", &xiaoV[i].ai, &xiaoV[i].bi); sum+=xiaoV[i].ai; } //如果小V同学的各科平时成绩就可以达到拿奖学金的程度。那就不用复习了if (sum/n>=avg) printf("0\n");
否则:那就要复习了,题目要求:至少要花多少时间复习?
所以,我们复习啊,必须要从涨分容易的科目开始,花的时间少,还能涨分,那我们优先要先找到那些涨分代价小的复习,然后记录一下复习花的时间,每涨一分,咱们就判断一下是否达到拿奖学金的程度,如果可以拿到奖学金,咱们就中止复习操作,然后输出花的时间即可。如果没有拿到,咱们就继续复习,涨分,判断,然后等该门课复习至满分后,继续复习下一门涨分代价小的复习重复操作。
这个点主要的是找复习代价小的,通过什么判断呢,xiaoV[i].bi,小V需要花多少时间复习该门课涨一分。这个值越小越好啊,博主也没啥别的本事,排序耍的还行,我们直接将xiaoV的所以有科目按照xiaoV[i].bi,让xiaoV[i];从小到大排序,然后遍历,执行我上面说的操作。
大家应该能够理解吧?理解的同学扣波1 ,咱们互动一下。编辑
程序实现:
typedefstructstudent{ intai;//每门课的平时成绩intbi;//该门功课如果要涨分要花的时间}student; intmain() { intn=0;//多少门功课intr=0;//满分intavg=0;//拿奖学金的平均分while(scanf("%d %d %d",&n,&r,&avg)!=EOF) { //小V有几门科目,咱们就开辟多大的空间,存储每一门的平均分数,和对应复习涨分所需要的时间student*xiaoV=(student*)malloc(sizeof(student)*n); if(xiaoV==NULL)//如果开辟失败就没必要继续了 { perror("malloc");//报个错exit(-1); } intsum=0;//统计小V同学各科的平时成绩和for(inti=0;i<n;++i) { scanf("%d %d",&xiaoV[i].ai,&xiaoV[i].bi); sum+=xiaoV[i].ai; } //如果小V同学的各科平时成绩就可以达到拿奖学金的程度。那就不用复习了if(sum/n>=avg) printf("0\n"); else { //冒泡排序,使涨分花时间代价小的排在前面,优先处理//当然也可以使用qsort()库函数排序for(inti=0;i<n;++i) { for(intj=0;j<n-i-1;++j) { if(xiaoV[j].bi>xiaoV[j+1].bi)//小的放在前面 { studenttmp=xiaoV[j];//定义结构体student类型的变量临时存储、交换xiaoV[j]=xiaoV[j+1]; xiaoV[j+1]=tmp; } } } longtime=0;//记录复习提分所需要的时间、因为输入案例较大所以使用long 型for(inti=0;i<n;++i)//判断某一门科目 { //不会拿到超过满分的分数作为判断该科目能涨多少分的结束条件for(intj=xiaoV[i].ai+1; j<=r ;++j)//判断该门科目能涨多少分,并且记录所花的时间代价 { time+=xiaoV[i].bi;//统计该科涨分的时间代价++sum;//花时间复习就涨一分if(sum/n>=avg)//每涨一分我们就看看是否达到拿奖学金的最低分数 { printf("%ld\n",time); free(xiaoV);//释放掉我们动态开辟的空间gotoend;//我们使用goto跳转出循环 } } } } end: ; //跳转至多组while循环的末尾,使其可以继续多组输入 } return0; }
goto语句
这里博主使用了goto 语句,关于goto 语句,博主简单讲两下:
C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。 从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过 程。 例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。就像博主遇到的情况,已经达到可以拿到奖学金的程度,就没必要复习了。如果break;中止内部循环,实际上,外循环还是会继续运行的,没必要了。
goto语言真正适合的场景如下:
for(...) {
for(...) {
for(...) {
if(disaster)
goto error;
}
} …
}
error: ;
感兴趣的朋友可以用博主的方法,或者是自己的方法做做这道题,优化一下代码。
题目来源于牛客网
编辑
题目链接:奖学金_牛客题霸_牛客网 (nowcoder.com)
本期收录于博主的专栏——每日一题,适用于编程初学者,有兴趣的朋友们可以订阅,查看其它“精彩小题”。每日一题_保护小周ღ的博客-CSDN博客
感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★*
编辑
如有侵权请联系修改删除!