第1单元准备篇 一个算法花费的时间与算法中某些“时间固 定的基本操作”被执行的次数有关。这个“时间 固定的基本操作”被执行的次数少,花费的时间 就少;执行的次数多,花费的时间就多。在信息 学竞赛或程序设计水平展示活动中,对算法的时 间要求一般为 1 秒,1秒能执行某个“时间固定的 基本操作”的次数大概是107~108。 Xcyzw.indd 1 2021.11.11 4:30:44 PM 002 小学生C++趣味编程训练营 第1 课我爱编程 ——格式化输入 / 输出 观世事万物,皆有算法。 问心有何属?唯有编程。 尼克是一位编程爱好者,每周都要到“我爱编程”训练中 心学习编程。已知他学习开始时间和学习时间,请你帮他算一 算学习结束时间。 【输入格式】 共两行。 第一行,一个格式为“时: 分”的时间,表示学习开始时间(0G 时< 24,0G 分<60)。 第二行,一个整数,表示学习所用的分钟数(0G 分<105)。 【输出格式】 一行,一个格式为“时: 分”的时间,表示学习结束时间,小时和 分钟输出时均占两位宽度,不足两位时用0 补齐。 【输入及输出样例】 输入样例 输出样例 08:30 09:10 40 输入和输出的时间格式均为“时: 分”,小时与分钟之间有一个冒号(如 08:30),使用cin 和cout 语句输入或输出时间(时: 分)这种指定格式的数 据不太方便,而使用格式化输入函数scanf 和格式化输出函数printf 就很方便。 #include // 万能头文件 using namespace std; // 本程序不需要此语句,可以省略 Xcyzw.indd 2 2021.11.11 4:30:44 PM 第 1 单元 准备篇003 int main() { int h1, m1, h2, m2, n; scanf("%d:%d%d", &h1, &m1, &n); h2 = h1 + (m1 + n) / 60; m2 = (m1 + n) % 60; if(h2 >= 24) h2 = h2 % 24; printf("%02d:%02d\n", h2, m2); // 转义符\n , 表示换行 return 0; } 其思路是先用格式化输入函数scanf 输入开始时间和学习时间,自动过 滤掉小时与分钟的分隔符——冒号,然后计算出结束时间,最后用格式化输 出函数printf 按“时:分”格式输出结束时间。 scanf 函数的使用方法如下。 scanf(" 格式控制字符串",变量地址列表); 变量地址的表示方法一般是在变量前加取地址运算符&,涉及多个变量 地址时,用逗号隔开,而格式控制字符串是按照变量的顺序、与变量的数据 类型相匹配的控制符,如图1.1 所示。 %d 表示需要输入一个输入的第1 个数赋值给整型变量h1 ,第 int 型(整型)数据2 个数赋值给整型变量m1 ,第3 个数赋 值给整型变量n scanf("%d:%d%d", &h1, &m1, &n); 输入的第1 个两个格式控制符%d 紧以变量地址每个变量地 数与第2 个数挨着,表示输入的第2 个的形式出现,址之间用逗 之间需要用数与第3 个数之间用空& 是地址运号分隔 冒号分隔格或换行分隔算符 图1.1 scanf 函数中常见数据类型的格式符及使用范例如表1.1 所示。 Xcyzw.indd 3 2021.11.11 4:30:44 PM 004 小学生C++趣味编程训练营 表1.1 数据类型格式符scanf 函数使用范例 int %d scanf("%d",&n); long long %lld scanf("%lld",&ln); float %f scanf("%f",&fn); double %lf scanf("%lf",&dn); char %c scanf("%c",&ch); char 数组%s scanf("%s",str); 数组名称本身代表了这个数组第一个元素的地址,所以字符数组名前没 有取地址运算符&。%s 通过空格或换行来识别一个字符串的结束。 printf 函数的使用方法如下。 printf(" 格式控制字符串",输出列表); 格式控制字符串用于指定输出格式,如图1.2 所示。 格式控制符和变量的数据类型要一致,第1 个格式控制 符对应第1 个变量,第2 个格式控制符对应第2 个变量 printf("%02d:%02d\n", h2, m2) %02d 表示输出的变量类型为int 型,在第1 个数与第\n 表示每个输出 输出时占两位宽度 , 不足两位时用2 个数之间会输换行项之间用 0 补齐 , 超出两位时按原值输出出一个冒号逗号分隔 图1.2 printf 函数中常见数据类型的格式符及使用范例如表1.2 所示。 表1.2 数据类型格式符printf 函数使用范例 int %d printf("%d", n); long long %lld printf("%lld", ln); float %f printf("%f", fn); double %f printf("%f", dn); char %c printf("%c", ch); char 数组%s printf("%s", str); Xcyzw.indd 4 2021.11.11 4:30:44 PM 第 1 单元 准备篇005 需要注意的是,string 字符串不能直接使用scanf 函数输入或printf 函数 输出。 使用print 函数输出时,如何控制场宽?如何保留小数位数? printf 函数常用的输出格式有以下几种。 1. %md 。%md 可以使int 型数据按m 位右对齐的方式输出。当int 型数 据不足m 位时,高位用空格补齐;超过m 位时,则保持原样。 2. %0md 。%0md 的作用与%md 类似,唯一的不同在于,当数据的值不 足m 位时,在前面用0 补足。 3. %.mf 。%.mf 可以让浮点数保留m 位小数,这个“保留”使用的是精 度的“四舍六入五成双”规则(具体细节不必掌握)。当题目中要求输出的 浮点数要保留几位小数或精确到小数点后几位时,就可以用这个格式进行 输出。 4. %m.nf 。%m.nf 可以让浮点数按m 位右对齐的方式输出,其中小数点 占1 位,小数部分占n 位。当数据的整数部分不足m–n–1 位时,则高位用 空格补齐;当数据的整数部分超过m–n–1 位时,则保持原样。 #include using namespace std; int main( ) { int n1 = 8, n2 = 9; double d1 = 3.1415926; printf("%2d:%2d\n", n1, n2) ; printf("%02d:%02d\n", n1, n2) ; printf("%.2f\n", d1) ; printf("%7.2f\n", d1); // 输出的数据占7 位,其中小数部分占2 位 return 0; } 输出: Xcyzw.indd 5 2021.11.11 4:30:44 PM 006 小学生C++趣味编程训练营 8: 9 08:09 3.14 3.14 scanf 和printf 函数使用起来比cin 和cout 语句要复杂一些,但scanf 和 printf 函数比cin 和cout 语句执行速度更快。当输入或输出的数据很多时, 如果使用cin 或cout 会很耗时,程序提交到在线测试平台或评测系统中,可 能会出现输入或输出没结束就超时了的现象。所以,当输入或输出的数据很 多时,建议使用scanf 函数进行输入,使用printf 函数进行输出。 为了能在程序中正常地使用scanf 和printf 函数,需要包含头文件 ,即#include ,也可以使用万能头文件#include 。 小提示 因为#include 包含了目前C++ 所包含的所有头文 件,故称为万能头文件。为了减少不必要的识记,建议以后都使用万 能头文件。 英汉小词典 scanf [.sk.nef] 格式化输入 printf [.printef] 格式化输出 ? 动动脑 作业 “ 健康码” 【问题描述】 为了鼓励同学们按时完成网上作业,狐狸老师设计了作业“健康码” , 当天19:30 前按时完成的“健康码”为“绿码”,19:30 至20:30 完成的为 “黄码”,20:30 以后完成的为“红码”。 【输入格式】 输入一个“时: 分”格式的时间,输入的时间确保在当天16:00 至24:00 。 Xcyzw.indd 6 2021.11.11 4:30:45 PM 第 1 单元 准备篇007 【输出格式】 当健康码为 “ 绿码 ” 时 , 输出Green 。 当健康码为 “ 黄码 ” 时 , 输出Yellow 。 当健康码为 “ 红码 ” 时 , 输出Red 。 【输入及输出样例】 16:10 20:10 23:01 输入样例1 输入样例2 输入样例3 Green Yellow Red 输出样例1 输出样例2 输出样例3 Xcyzw.indd 7 2021.11.11 4:30:45 PM 008 小学生C++趣味编程训练营 第2 课纸上看人生 ——初识二维数组 如果按照平均寿命75 岁来计算,人生其实只有900 个月,我们在纸上 画一个30×30 的表格,每个格子代表一个月,每过一个月就把一个格子涂 上颜色,就可以一目了然地看出自己已经度过的岁月。尼克刚好12 周岁, 涂在表格中如图1.3 所示。 图1.3 Xcyzw.indd 8 2021.11.11 4:30:45 PM 第 1 单元 准备篇009 如果涂上颜色的单元格用1 表示,未涂上颜色的单元格用 0 表示,那么应该如何存储这30×30 个单元格中的信息? 是定义900 个不同的变量来存储?或者定义30 个每个长度为30 的一维 数组来存储?还是. . 最好的办法是定义一个30×30 的二维数组来存储所有单元格中的信息。 定义二维数组的一般格式如下。 类型标识符数组名[ 常量表达式1][ 常量表达式2] 图1.3 中所有单元格的值只可能是0 或1,因此可以定义一个bool 型的 二维数组,例如: bool a[30][30]; 此时,定义a 为30×30(30 行30 列)的二维数组。二维数组可以视为 一种特殊的一维数组,该数组的元素又是一个数组。如二维数组a[30][30] 中包含a[0]~a[29] 共30 个一维数组,数组a[0] 又有30 个元素,分别是a[0][0] , a[0][1],a[0][2],.,a[0][29] 。为了便于同学们理解二维数组a,我们可以画 一个二维表格,如图1.4 所示。 0123 . 29 0 1 2 29 a[0][0] a[0][1] a[0][2] a[0][3] . a[0][29] a[1][0] a[1][1] a[1][2] a[1][3] . a[1][29] a[2][0] a[2][1] a[2][2] a[2][3] . a[2][29] . . . . . . a[29][0] a[29][1] a[29][2] a[29][3] . a[29][29] 图1.4 Xcyzw.indd 9 2021.11.11 4:30:45 PM 010 小学生C++趣味编程训练营 在程序中,可以通过双重循环对二维数组中的每一个元素进行赋值,也 可以通过双重循环输出二维数组中的每一个元素。 #include using namespace std; bool a[40][40]; // 数组定义得稍大一 点 int main( ) { int i, j, year, cnt = 0; scanf("%d", &year) ; for(i = 1; i <= 30; i++ ) for(j = 1; j <= 30; j++) { cnt++ ; if(cnt <= year * 12) a[i][j] = 1; //true else a[i][j] = 0; //false } for(i = 1; i <= 30; i++ ) { for(j = 1; j <= 30; j++ ) printf("%d", a[i][j]) ; printf("\n") ; } return 0; } 对二维数组进行初始化时也可以使用“初始化列表”。例如: int b[3][2] = {{0, 1} , {2, 3} , {4, 5}}; // 分行初始化 或 int b[3][2] = {0, 1, 2, 3, 4, 5}; // 不分行初始化 为了更加直观,我们可以画一个3 行2 列的二维表格,呈现数组的元素 及赋值情况,如图1.5 所示。 Xcyzw.indd 10 2021.11.11 4:30:45 PM