1
C语言程序设计
1.5.9 习 题 四

习 题 四

4.1 将一个数组中的值按逆序重新存放。例如,原来顺序为8,5,4,6,1,要求改为1,6,4,5,8。

算法提示

要将一个数组中的所有元素按逆序存放,只需将数组的第1个元素与最后一个元素交换,第二个元素与倒数第二个元素交换,以此类推,直到数组最中间的元素为止。

4.2 N盏灯排成一排,从1到N依次编号。有N个人也从1到N依次编号。第一个人(1号)将灯全部打开,第二个人(2号)将凡是2和2的倍数的灯关闭。第三个人(3号)将凡是3和3的倍数的灯做相反处理(即将打开的灯关闭,关闭的灯打开),以后的人都和3号一样,将凡是与自己编号相同的灯和是自己编号倍数的灯做相反处理,请问当第N个人操作之后,哪几盏灯是点亮的?试编程求解这个问题,N由键盘输入。

算法提示

这个题与用筛法求素数类似。

用一维数组Lamp表示每盏灯的状态,Lamp[i]=0表示第i盏灯是关闭的,为1表示第i盏灯是打开的。开始时所有的灯都是关闭的,所以先把Lamp数组中所有元素赋值为0。

接下来,用一个一重循环依次处理每个人的操作:for(i=1;i〈=n;i++),其中i表示当前操作者的编号。根据题意,第i号人要让第i号灯和与i有倍数关系的灯改变状态。因此在处理某一个人的操作时,再用一个一重循环:for(j=i;j〈=n;j=j+i),其中j表示灯的编号。这里要改变状态即实现0与1之间的转换。

最后用一个一重循环输出结果。

4.3 用简单选择法对10个整数排序。

算法提示

选择排序是不断在待排序序列(无序区)中按递增(或递减)次序选择记录,放入有序区中,逐渐扩大有序区,直到整个记录区为有序区为止。

其基本思想是:每一趟(例如第i趟,i= 1,2,…,n−1)在后面n−i个待排序对象中选出最小的一个,作为有序序列的第i个。待到第n−1趟做完,待排序对象只剩下1个,就不用再选了。

4.4 所谓幻方,就是一个n行n列的正方形,当n为奇数时,称为奇数阶幻方。共有n2个格子,将1,2,3,…,n2这些数字放到这些格子里,使其每行的和、每列的和及两条对角线的和都是一个相同的数。试编程由键盘输入一个奇数n,输出一个n阶幻方。

算法提示

多少年来,许多数学家都在研究这个古老而有趣的问题,试图找出一般的解法,但仅仅解决了当n是奇数和n是4的倍数的情况。现在介绍当n是奇数时的解法。

(1)将1放在第一行中间一个格子里。

(2)依次将后一个数放到前一个数的右上格,如:将2放到1的右上格,将3放到2的右上格,等等。

可能出现下面的情况:

①若右上格从上面超出,则将后一数放到与右上格同列的最后一行。

②若右上格从右面超出,则将后一数放到与右上格同行的第一列。

③若右上格既从右面超出又从上面超出,则将后一数放到前一数的下面。

④若右上格已被数字填充,则将后一数放到前一数的下面。

当然,这种写法只是其中一个答案,而不是唯一答案。下面就是一个五阶幻方。

img405

4.5 输入一个字符串,要求按相反的顺序输出各个字符。例如,输入为AbcD,则输出为DcbA。

算法提示

这个题与习题4.1类似,但需注意的是:

(1) 存储要输入的字符串的字符数组的长度要足够大

(2) 存储字符串的数组的大小与字符串长度之间的关系

4.6 输入一行字符,统计其中包括多少单词,单词之间用空格分隔。

算法提示

单词的数目可以由空格出现的次数决定(连续的若干个空格作为出现一次空格,一行开头的空格不统计在内)。因此,本题的关键是如何对连续的空格进行处理。这可以设置一个变量space来表示,当读入到第一个空格时,将space的值置为1,表示读到了空格,以后再读到空格时判断space的值是否为1,以此确定是否连续空格,若不是连续空格,则单词数增1;当读到非空格时,将space置为0,space的初值设为0。

4.7 编写一个学生管理系统,其中学生的信息有姓名(汉字或汉语拼音,最多20个字符)、性别(男/女,用1表示男,0表示女)、生日(19850101(年月日))、身高(以m为单位),还需要处理C语言、微积分两门课的成绩,请编写程序实现以下功能:

首先从键盘输入学生的人数,然后依次输入每个学生的数据,输出每门课程的总平均成绩、最高分和最低分,以及获得最高分的学生的信息。需要注意的是某门课得最高分的学生可能不只一人。

4.8 在用C语言编制图像处理程序时,常使用结构来表示平面上的点。试编程求解下面的问题:

(1)输入两个点的坐标,求这两点间的距离。

(2)输入三个点的坐标,判断这三个点是否共线。

算法提示

判断三点共线,可由其中两点得到直线方程,再判断第三点是否在直线上即可。

4.9 用一个数组存放图书的信息,每本书包含书名、作者、出版年月、出版社、借出数目、库存数目等信息。编写程序存放若干本书的信息,按书名排序后输出。

算法提示

注意,这里要对书名进行排序,而书名是字符串,因此要使用字符串比较函数strcmp,而不要直接对两个字符串进行比较。

4.10 战士分子弹问题。在某次实弹射击训练中,班长将十个战士围成一圈发子弹。

首先,班长给第一个战士10颗,第二个战士2颗,第三个战士8颗,第四个战士22颗,第五个战士16颗,第六个战士4颗,第七个战士10颗,第八个战士6颗,第九个战士14颗,第十个战士20颗。

然后按如下方法将每个战士手中的子弹进行调整:

所有的战士检查自己手中的子弹数,如果子弹数为奇数,则向班长再要一颗。然后每个战士再同时将自己手中的子弹分一半给下一个战士(第10 个战士将手中的子弹分一半给第1个战士)。

问需要多少次调整后,每个战士手中的子弹数都相等?每人各有多少颗子弹?要求输出每轮调整后各战士手中的子弹数。结果的输出格式为

img406

算法提示

为简单起见,在进行一轮分发时,可先判断每位战士的子弹数是否为偶数,若不是,则将这位战士的子弹数加1。

然后,再考虑每个战士将自己的子弹同时分一半给下一个战士,这样每个战士的子弹数将是他原来的子弹数和他的上一位战士的子弹数的平均数,如第2位战士的子弹数将是第1位战士的子弹数10和他本身的子弹数2的平均数6,第1位战士的子弹数将是第1位战士的子弹数10和最后一位战士的子弹数20的平均数即15,以此类推。

因此,这个题可使用双重循环,外层循环的结束条件是所有战士的子弹数相等,在循环中,先判断每位战士子弹数的奇偶性并作相应处理,再用一个计数循环,对每位战士的子弹数循环赋值。

4.11 保龄球计分问题。在保龄球比赛中,已知每次击倒的保龄球数,计算在一局比赛中一个人的得分,要算出每一轮的得分和每一轮之后的累加得分。

保龄球比赛一局共10轮,前9轮中每一轮最多滚两次球;第10轮可以滚两次或3次球。每轮计分规则如下:

(1)如果一轮中第一个球击倒全部10只保龄球,称为Strike(好球),则这一轮的得分等于10加上下两轮击倒保龄球的只数。

(2)如果一轮中两个球击倒全部10只保龄球,称为Spare(成功),则这一轮的得分等于10加下一轮被击倒保龄球的只数。

(3)如果一轮中两个球一共击倒保龄球只数少于10,称为Normal(平常),则这一轮的得分等于本轮所击倒保龄球的总只数。

程序要求输入20个不大于10的整数,表示一局中每一轮击倒的球数,最后输出这一局的各轮的得分以及该局的总分。

4.12 素数排列问题。现将不超过2000的所有素数从小到大排成第一行,第二行上的每个数都等于它“右肩”上的数和它“左肩”上的数的差,这样可以得到两行数,如下表所示:

img407

试编程求解:在第二行中是否有多个连续的数之和等于1898?如有,将所有的可能组合均输出。

算法提示

首先用筛法求出2000以内的所有素数,再根据前面计算的结果算出第二行的所有数,存放在一个数组中。

然后通过一个双重循环来判断是否有多个连续的数之和等于1898这个问题。

外层循环,对存储第二行的数的下标进行枚举,依次从第二行的第一个数,第二个数开始进行处理,直到所有的数处理完成为止。

内层循环中从当前元素依次向右进行累加,直到累加和大于或等于1898为止。如果累加和等于1898,则输出之,否则退出内层循环,继续外层循环的处理。