写在读前:
- 本文主要面对广大c语言初学者,文中除部分特例代码采用c++书写外,大部分代码均采用c语言,大家可放心食用。
- 题解内容包含:题目与考点分析、算法思路讲解、参考程序的代码模块设计、注意事项,在以上所有部分都讲解完成后,在一道题的最后会给出参考代码,同时部分题目兼有背景补充或拓展知识,希望可以帮助您全面深入的理解到每一个考点。
- 在每道题的讲解部分会给出各种方法非常详细的讲解,从思想到实现逐步分析,请结合代码与文字一起食用。
- 文中代码均有较为详细的注释,如果在看不懂的情况下,不妨先结合注释转动下灵活的头脑,同时也非常欢迎读者在评论区留下异议或者其他见解。
更新目录:
2020.12.08 修改了部分错别字以及与比赛题目题面不符的内容;
2020.12.10 在文章末尾新添加赛后回顾部分;
这里是目录:
A. 阿正的忐忑不安
题目分析:
给出五个正整数,让你判断前四个数与第五个数的大小关系,若是前四个数大于等于第五个数,则输出一段文本,否则输出另一段文本。
本题意在考察最基本的顺序、分支与逻辑设计,难度属于低级梯队。
思路讲解:
使用一个if结构即可,判断条件位前四个数的和是否大于第五个数。
对于数据类型的选择,本题考察重点并非数据范围,虽然题目中表明了数据的大小,但对分支语句判断等核心算法并未造成影响。采用int类型的整数即可处理所有输入与运算。
代码模块:
输入与初始化——判断——输出
注意事项:
在输出时有一个略坑的地方需要考虑,便是引号的输出。采用printf函数中输出引号需要用到转义字符的输出方法,类似但又不同于换行符,引号的输出需要采用如下格式:
printf(" \" "):
//运行结果:
"
printf函数内写下了一个空格,一个反斜杠,一个引号,一个空格,最后的运行输出结果是一个空格,一个引号,一个空格。
参考代码:
#include<stdio.h>
int sum=0,goal;
//sum来储存阿正的总分; goal来储存录取分数线,即第五个输入值
int main()
{
for(int i=0;i<4;i++){
//四科分数,定义临时变量temp分四次来参与输入与计算
int temp;
scanf("%d",&temp); //输入
sum+=temp; //计算
}
//以下代码与上等效
/* int a,b,c,d; ` //也可以定义四个变量分别输入计算
scanf("%d%d%d%d",&a,&b,&c,&d);
sum=a+b+c+d; */
scanf("%d",&goal); //输入分数线的值
//在if框体内只有一条语句时,可以省略大括号
if(sum>=goal) printf("Blessings for your college career!\n"); //大于等于的情况
else printf("Blessings for your \"fourth grade\" in high school!\n"); //小于的情况
return 0; //必须return 0;
}
拓展与背景补充(引自百度百科):
半角字符:半角字符是指一字符占用一个标准的字符位置,通常的英文字母、数字键、符号键都是半角的,半角的显示内码都是一个字节。
转义字符:所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。而C中定义了一些字母前加"\"来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。
B. 阿正的学期准备
题目分析:
题目给了你几种具有一定规律的优惠方案与阿正所持有的金币数量,我们需要根据金币数量组合出可以获利最大的优惠方案,并输出最后连本带利的金币数量。
我们细看题目中给出的五种优惠方案,可以发现获赠金币与充值金币是成正比的,只有发现了这个规律,分析才能继续进行,我们后续的算法设计皆是建立在此基础之上的。
本题更加灵活的考察了代码设计能力与最简单的贪心思想,选手可以从分支循环等多个角度灵活地书写代码,难度属于低级梯队中最难的一道题。
而何谓”贪心“思想与具体解题方法,请参考下文:
思路讲解:
在获赠金币与充值金币是成正比的基础上,肯定是充值的越多,获利越多。因此我们在已有可以用来充值的金币数固定的情况下,选择充值金币数量多的方案肯定是获利最多的,只要服从”金币数量够,就选最大的“原则,便可以获得最大的利润。
上述叙述就是一个简单的贪心案例,所谓”贪心“,就是当前情况选择可以获利最大的即可,不需要考虑对后续的影响。
在了解了我们设计代码的核心思想后,我们只需要服从上述原则进行设计即可,在这里笔者提供两种思路,读者不必仅局限于此:
在得到可利用最大金币数量后,我们可以自多至少地依次判断金币数量是否满足优惠条件,即从充值金币数量最大的开始判断,如果符合优惠条件,那么便将此项优惠记录,并减少已有的金币数量,继而判断下一项优惠是否满足,直至五项优惠全部判断完。
上文叙述了采用纯分支语句的判断方法,我们按照从多到少的顺序写下五个分支语句便可。同时,我们也可以将这些参数存储到数组中,然后采用循环依次判断是否符合优惠条件:
首先建立两个数组分别来存储充值所需金额与对应的获利金额,此处要注意,我们循环的方向要与上文分支中判断的方向一致,即仍然从大到小进行判断,所以我们在存储数据时可以将数据倒置一下,即将第五种优惠的参数存储到数组下标位0的位置,将第一种优惠的参数存储到数组下标为4的位置。继而,再进行循环依次遍历。
并且对于数据类型的选择,与本次比赛大部分题目相同,本题中明确给出了所有数据均在整形范围内,因此选择整形便足够了。
代码模块:
输入与初始化——数据处理——输出
注意事项:
分支语句的写法不必多言,只需要在进入当前分支后记得减去花费掉的金币数,加上获得的金币数即可。
但若是采用循环的整体框架,则写法更加灵活,可以在循环语句里进行分支判断,也可以进行其他更优的操作。
参考代码:
分支书写:
#include<stdio.h>
int n; //n即为最初的金币总数
int main()
{
scanf("%d",&n);
int now=n,result=n;
//now为执行过程中实时更新的金币数量, result即为购物卡中实时更新的金币数量,即"连本带利"的金币数
//此处将result初始化为n,后续计算中只用考虑获利即可;
//如果初始化为0,则在分支中不仅要添加"本金的部分", 在遍历完五个方案后,还要加上五个方案没花完的"剩余的部分"
if(now>=648) now-=648,result+=108; //从多到少依次判断, 如果符合条件更改两个参数的值
if(now>=324) now-=324,result+= 54;
if(now>=108) now-=108,result+= 18;
if(now>= 36) now-= 36,result+= 6;
if(now>= 6) now-= 6,result+= 1;
printf("%d\n",result); //输出结果
return 0; //必须return 0;
}
循环书写:
#include<stdio.h>
int n,pointer=0; //与上同理,n为初始金币数,而pointer则记录遍历到哪种优惠情况
int cost[6]={
648,324,108,36,6,0},extra[6]={
108,54,18,6,1,0};
//cost存储需要充值数量,extra存储额外获利的金币数量;
//并且将最后一位留给0的位置,pointer指向最后一位,便说明金币已经花完了,不能再进行充值了
int main()
{
scanf("%d",&n);
int now=n,result=0; //now为过程中实时更新的所持有的金币数量,result为实时更新的购物卡中金币总数
while(pointer<6){
//只有pointer小于5时才能进行充值
while(cost[pointer]>now) pointer++; //寻找当前金币数可以选择的最大优惠方案,包括数组第六位的"0"方案,即代表不能再进行充值
now-=cost[pointer]; //更新两个参数的值,此处result需要"连本带利"地进行更新
result+=(extra[pointer]+cost[pointer++]);
}
result+=now; //并且最后加上能享受的优惠都享受后, 剩余的金币数
printf("%d\n",result); //最后输出结果
return 0; //必须return 0;<