1.题目链接
2.解题思路
2.1 题意解析
本题的目的是要完成报时功能,即根据输入的小时数h和分钟数m的值,按照报时规则输出对应的英文输出。这里需要注意题目中关于输入的说明“非零的数字前没有前导0,h小于24,m小于60”,这意味着“21:05”对应的输入应该是“21 5”,这样规定实质上降低了编码解题的难度。我们再来看输出,构成输出的要素如下表所示,
数字 | 英文 | 数字 | 英文 | 数字 | 英文 |
---|---|---|---|---|---|
0 | zero | 1 | one | 2 | two |
3 | three | 4 | four | 5 | five |
6 | six | 7 | seven | 8 | eight |
9 | nine | 10 | ten | 11 | eleven |
12 | twelve | 13 | thirteen | 14 | fourteen |
15 | fifteen | 16 | sixteen | 17 | seventeen |
18 | eighteen | 19 | nineteen | 20 | twenty |
30 | thirty | 40 | forty | 50 | fifty |
时刻 | o'clock |
本题期待的输出即为表中给出元素按规则的组合。
2.2 报时逻辑
弄清楚题意后,我们可以简单总结一下报时的基本规则,主要分为整点报时和非整点报时两种情况,下面逐一说明:
- 整点报时:当m为0表示整点报时,例如输入“3 0”表示的是“3:00”,程序应该输出“three o'clock”。
- 非整点报时:当m不为0表示非整点报时,此时又分为两种情况考虑。
- m小于20:此时m的取值可以是1、2、3、4、5、6、7、8、9、10、11、12、13、14、15、16、17、18、或19,我们应该采用one、two、three、four、five、six、seven、eight、nine、ten、eleven、twelve、thirteen、fourteen、fifteen、sixteen、seventeen、eighteen、nineteen。
- m大于20且m为20、30、40或50等10的倍数时:我们应该采用twenty、thirty、forty或fifty。
- m大于20且m的值无法被10整除的情况:这时我们要分别采用整除(
m / 10
)和取余(m % 10
)确定十位和个位的数值,然后输出对应的英文表示。
3. 编程实现
3.1 实现过程
- 首先定义两个
int
型变量,实现小时数和分钟数这两个变量的输入。
//h保存小时数,m保存分钟数
int h, m;
- 这里我们考虑一下最复杂的情况,即小时数h不为0,分钟数m不为0,h大于20且小于24,m大于20且小于60,这种情况我们要分别确定h和m的十位数和个位数,所以我们定义四个
int
型变量来保存这些数。
//hshiwei保存小时数的十位,hgewei保存小时数的个位,mshiwei保存分钟数的十位,mgewei保存分钟数的个位
int hshiwei, hgewei, mshiwei, mgewei;
- 输入题目所给的两个变量。
//输入小时数和分钟数
scanf("%d%d", &h, &m);
- 为了方便后续的代码实现,这里我们将所有英文表示存放在数组中,这里也是本题的难点1:使用
char
型二维数组存储数据。
- 首先,我们评估一下,需要存储的英文单词包括zero、one、two、three、four、five、six、seven、eight、nine、ten、eleven、twelve、thirteen、fourteen、fifteen、sixteen、seventeen、eighteen、nineteen、twenty、thirty、forty、fifty和o'clock,一共有25个,因此我们确定
char
型二维数组的第一个维度是20。 - 其次,我们再看这25个英文单词中,字符个数做多的是seventeen,一共有9个字符,我们如果想存放它需要定义一个可以容纳10个字符的数组,即
char str[10] = "seventeen";
。为什么数组空间要是10,而不是9呢,seventeen不是9个字符吗?因为在使用字符型数组存放字符串时,如果采用字符串常量来初始化字符数组的方式,系统对于字符串常量会自动加一个'\0'作为结束符,所以"seventeen"看起来是9个字符,其实是由's'、'e'、'v'、'e'、'n'、't'、'e'、'e'、'n'和'\0'共10个字符构成的,因此str这个字符型数组容量要设定为10才可以,否则会编译错误。那么如果我就想把数组容量设置为9呢,那么就要采用下面这两种比较繁琐的方式来初始化。这两种方式尽管语法没有错误,但是从代码编写简洁性和可读性的角度来说不可取。
char str[9];
str[0] = 's';
str[1] = 'e';
str[2] = 'v';
str[3] = 'e';
str[4] = 'n';
str[5] = 't';
str[6] = 'e';
str[7] = 'e';
str[8] = 'n';
char str[9] = {'s', 'e', 'v', 'e', 'n', 't', 'e', 'e', 'n'};
- 综上所述,所有英文单词中,seventeen这个字符串的字符数量最多,需要至少10个空间,因此我们要定义的二维字符数组的第二个维度大小可以确定为10。这里我们给出字符型二维数组的定义和初始化代码如下。通过这种定义方式,我们就可以利用数组的索引来调用英文单词了。例如,
timeword[0]
就是zero,timeword[0][3]
表示的就是'o'。
char timeword[25][10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "thirty", "forty", "fifty", "o'clock"};`
- 上述准备工作完成后,就可以开始报时逻辑的编程模拟了。我们还是把问题分成两部分,先实现小时的输出。关于小时的输出,需要注意的是,它根据h的大小分为两种情况,我们先看h小于20的情况。
//如果小时数小于20
if(h < 20)
{
printf("%s", timeword[h])
}
当h<20的时候,我们会发现timeword[h]
的值正式h这个值对应的英文单词,那么将h可以作为数组的索引值,输出timeword[h]
的值即可。
- 再看h大于20的情况,即h大于等于20且h小于60的时候,实现代码如下。
else //如果小时数在20-60之间
{
//求小时数的十位和个位数字
hshiwei = h / 10;
hgewei = h % 10;
//输出小时数的十位数字
printf("%s", timeword[18 + hshiwei]);
//如果小时数的个位数字不为0,则输出
if(hgewei != 0)
{
printf(" %s", timeword[hgewei]);
}
}
hshiwei = h / 10;
:这里我们利用除法h / 10
得到h的十位数字,注意h是整型,10是整形,那么h / 10
的结果还是整型。大家可以尝试一下在Dev C++中运行printf("%d", 8 / 3);
,结果是2,尽管8/3的真实结果是2.6,但是由于8和3都是整型,所以在程序中只返回整数部分,小数部分不会满五进一。所以h / 10
的结果就是h在十位上的数字。hgewei = h % 10;
:这里我们利用取余操作,最终可以得到h在个位上的数字。timeword[18 + hshiwei]
:这里怎么出来个18呢?我们来看一个例子,假设此时h的值为23,那么根据上述两部可知变量hshiwei的值为2,hgewei的值为3。我们要输出十位上数字对应的英文单词,那么要确定数组的索引是什么。twenty在数组中的索引应该是20,而此时hshiwei的值为2,所以我们反推一下,即可得到要输出的字符串是timeword[18 + hshiwei]
。- 接下来要判断一下个位数字是否为0,如果不为0那就需要输出,如果为0,则不输出。各位数字可能的取值为1、2、3、4、5、6、7、8或9,那么这些数字的英文可以通过
timeword[hgewei]
来获得,hgewei可以刚好作为数组的索引来指定要取到的值。输出timeword[hgewei]
的时候要注意,前面要有空格,不要忘记!直到这里,我们把小时数部分的报时功能已经完全实现了,接下来是分钟数。
- 如果分钟数m为0,上面处理完小时数后加上o'clcok即可,实现代码如下。
//如果分钟数为0,上面处理完小时数后加o'clcok即可
if(m == 0)
{
printf(" %s\n", timeword[24]);
}
o'clock在timeword中放在索引为24的位置,所以timeword[24]
的值就是o'clock。输出的时候要避免格式错误,上面小时输出完毕后,是没有任何空格或换行的。这里输出timeword[24]
的值时,前面要加空格,后面加换行,这样的格式才是完整无误的,大家一定要注意这些细节,要不然就会PE。
- 如果分钟数m的值不为0,那么还需要再分成两种情况讨论,我们先看m小于20的这种情况,代码实现如下。
else //如果分钟数不为0,继续处理分钟数
{
//如果分钟数小于20
if(m < 20)
{
printf(" %s\n", timeword[m]);
}
与小时数的值小于20的情况类似,这时m可以直接作为数组的索引,timeword[m]
即为m这个数字的英文单词。需要注意的是,输出的时候要前面加空格,后面加换行。
- 再来看m大于等于20且小于60的情况。还是与小时数对于这种情况的处理类似,先分别利用整除和取余操作得到
mshiwei
和mgewei
。接下来先输出十位的数字对应的英文单词,注意前面要加空格。然后判断个位数字是否为0,如果不为0,那么输出个位数字对应的英文单词,也是前面加空格,后面加换行。如果个位数字为0,那么直接输出换行即可,实现代码如下。
else
{
//求分钟数的十位和个位数字
mshiwei = m / 10;
mgewei = m % 10;
//输出分钟数的十位数字
printf(" %s", timeword[18 + mshiwei]);
//如果分钟数的个位数字不为0,则输出
if(mgewei != 0)
{
printf(" %s\n", timeword[mgewei]);
}
else
{
printf("\n");
}
}
}
到这里全部的编程实现就结束了!
3.2 参考代码
#include<stdio.h>
int main()
{
//h保存小时数,m保存分钟数
int h, m;
//hshiwei保存小时数的十位,hgewei保存小时数的个位,mshiwei保存分钟数的十位,mgewei保存分钟数的个位
int hshiwei, hgewei, mshiwei, mgewei;
//输入小时数和分钟数
scanf("%d%d", &h, &m);
//将所有用到的跟时间相关的英文单词用一个二维char型数组保存
char timeword[25][10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "thirty", "forty", "fifty", "o'clock"};
//如果小时数小于20
if(h < 20)
{
printf("%s", timeword[h]);
}
else //如果小时数在20-60之间
{
//求小时数的十位和个位数字
hshiwei = h / 10;
hgewei = h % 10;
//输出小时数的十位数字
printf("%s", timeword[18 + hshiwei]);
//如果小时数的个位数字不为0,则输出
if(hgewei != 0)
{
printf(" %s", timeword[hgewei]);
}
}
//如果分钟数为0,上面处理完小时数后加o'clcok即可
if(m == 0)
{
printf(" %s\n", timeword[24]);
}
else //如果分钟数不为0,继续处理分钟数
{
//如果分钟数小于20
if(m < 20)
{
printf(" %s\n", timeword[m]);
}
else
{
//求分钟数的十位和个位数字
mshiwei = m / 10;
mgewei = m % 10;
//输出分钟数的十位数字
printf(" %s", timeword[18 + mshiwei]);
//如果分钟数的个位数字不为0,则输出
if(mgewei != 0)
{
printf(" %s\n", timeword[mgewei]);
}
else
{
printf("\n");
}
}
}
return 0;
}
4. 总结
4.1 考查的能力
- 字符串的存储、初始化,特别是'\0'这个C语言入门学习时经常遇到的坑;
- 数组以及二维数组的用法,包括定义、初始化和如何恰当地设计索引。
- 输入输出格式,什么时候该加空格,什么时候该加换行。
- 如何快速地读懂题意,将模拟的逻辑转换为
if else
这种分支结构。
4.2 解题技巧
- 第一道题经常是整场比赛的坑,一定要谨慎阅读题目,判断它属于什么类型的题目再做。先做简单的题目,最后再做难的题目,A掉简单的题目一方面可以积累信心,另一方面可以热身,将自己的状态一点点调整到最好的状态,去挑战难题。
- 一定要带草稿纸和笔,写下题目的关键点,将实现过程分为若干个步骤。逐部分实现,实现一部分,测试一部分。
- 自己要做一些测试样例,多测试一下自己的程序,不要题目给的样例数据通过了就提交。在比赛中,罚时经常是压垮比赛排名的最后一根稻草!!!