绝对零基础的C语言科班作业⑥循环结构(下)(九九乘法表,棱形图案,孪生素数)

一.多层循环

①(代码)输出每个数的真约数

任务描述

编程输入两个整数a和b(1<a<b),对于整数区间[a,b]内的所有整数x,依次输出x的所有真约数。

输入格式

一行中两个整数a和b,空格分隔。

输出格式

[a,b]区间内每个整数x输出一行,先输出x和冒号,然后依次输出它的所有真约数,约数间以一个空格分隔。

输入样例:

100 110

输出样例:

100:1 2 4 5 10 20 25 50

101:1

102:1 2 3 6 17 34 51

103:1

104:1 2 4 8 13 26 52

105:1 3 5 7 15 21 35

106:1 2 53

107:1

108:1 2 3 4 6 9 12 18 27 36 54

109:1

110:1 2 5 10 11 22 55

相关知识 循环嵌套

循环结构的循环体是一个语句或是一个复合语句,当然这个语句或复合语句中也可以是另外一个循环结构。如果是这样,就构成了循环结构的嵌套。

三种循环结构可以互相嵌套,例如:

以上列出了6种常见的循环嵌套情况,实际上还有很多种嵌套的情形。这也只是两层循环嵌套,还有3层甚至更多层次的循环嵌套在一起。

任务分析

对于这个任务,很显然对于[a,b]区间的每一个数x,我们要穷举(一一列举)处理,于是我们得到以下代码框架:

程序代码 外层循环(程序框架)

#include<stdio.h>
int main()
{
    int a,b,x,i;
    scanf("%d%d",&a,&b);     //输入整数a,b 
    for(x=a;x<=b;x++)   //外层循环穷举所有的x
    {       
        //处理x:输出x、冒号及x的所有真约数和回车
    }
    return 0;
}

接下来,我们就不需要考虑外层循环,只要思考如何处理x,输出x的所有真约数就可以了。这样,我们就把一个相对高维复杂的问题,降维分解为两个相对简单的问题。外层循环内,“输出x、冒号及x的所有真约数和回车”的问题,我们是熟悉的,可以通过下面的循环代码解决。

程序代码 内层循环(处理x)

        printf("%d:",x);          //输出x和冒号
        for(i=1;i<x;i++)          //内层循环输出n的所有真约数穷举[1,n-1]
            if(x%i==0)          //是约数就输出
            {           
                if(i>1)printf(" ");    //大于1的约数前才输出空格
                printf("%d",i);
            }
        printf("\n");             //输出回车

内层循环的代码,我们非常好理解,就是通过穷举[1,n-1]的所有整数,找到真约数(小于本身的约数)就输出,通过if语句控制空格的输出,这些方法都是我们已经熟悉的。我们把以上内层循环代码放到外层循环中,就得到完整代码。

程序代码 双层循环(完整代码)

#include<stdio.h>
int main()
{
    int a,b,x,i;
    scanf("%d%d",&a,&b);     //输入整数a,b 
    for(x=a;x<=b;x++)   //外层循环穷举所有的x
    {      
        //处理x:输出x、冒号及x的所有真约数和回车
        printf("%d:",x);          //输出x和冒号
        for(i=1;i<x;i++)          //内层循环输出n的所有真约数穷举[1,n-1]
            if(x%i==0)      //是约数就输出
            {           
                if(i>1)printf(" ");    //大于1的约数前才输出空格
                printf("%d",i);
            }
        printf("\n");             //输出回车
    }
    return 0;
}

代码测试与分析

输入:2 8 (可能的最小值2)输出:2:13:14:1 25:16:1 2 37:18:1 2 4输入:100 101 (可能的最小跨度)输出:100:1 2 4 5 10 20 25 50101:101

以上程序就是最典型的双层循环结构的代码,我们通过分析将问题降维分解为两个单层循环问题:外层循环:只负责穷举x,用单层for循环轻易解决,逻辑非常简单;内层循环:只负责输出x的真约数,通过穷举[1,n-1]的整数,用单层for循环可轻易解决,逻辑同样非常简单。可见,多重循环并不可怕,复杂的问题降维分解为若干简单问题的方法,我们要掌握。这样,编程就像搭积木一样简单。

②(代码)九九乘法表

任务描述

编程应用双层循环输出九九乘法表。

#include<stdio.h>
int main()
{
    int i, j, t;
    for (i = 1;i <= 9;i++)    //外层循环穷举变量i从1至9
    {
        //处理每一行(第i行)
        for (j = 1;j <= i;j++)   //内层循环输出第i行乘法表(j从1穷举到i共i项)
        {
            t = i * j;
            printf("%d*%d=%d", j, i, j * i);//输出一项(第i行第j列) 
            if (j < i)                    //控制每一项后面空格的输出 
            {
                if (t < 10)
                {
                    printf("  "); //积小于10输出2个空格 
                }
            }
            else
            {
                printf(" ");  //否则输出1个空格 
            }
        }
        printf("\n");      //输出回车 
    }
    return 0;
}

以上程序同样也是最典型的双层循环结构的代码,我们同样通过分析将问题降维分解为两个单层循环问题:外层循环:只负责穷举i从1到9,用单层for循环轻易解决,逻辑非常简单;内层循环:只负责输出第i行的乘法表(共i项),通过让j穷举从1到i,用单层for循环可轻易解决,逻辑同样非常简单。也可以简单理解为,外层循环负责控制行号,内层循环负责控制列号,内层循环体负责输出第i行第j列的算式。

③(代码)区间内素数

任务描述

编程输入两个整数a,b(2<=a<b),输出整数区间[a,b]内的所有素数(测试数据中保证区间内有素数)。

输入格式

两个整数a和b。

输出格式

区间[a,b]内的所有素数,逗号分隔。

#include<stdio.h>
#include<math.h>
int main()
{
    int a, b, n, i, f, k;
    scanf("%d%d", &a, &b);      //输入a,b 
    k = 0;                      //计数器清0 
    for (n = a;n <= b;n++)     //外层循环穷举区间[a,b]内所有的n
    {
        //如果n是素数就输出
        f = 1;                      //标志变量赋初值1 
        for (i = 2;i <= sqrt(n);i++)   //穷举2到根号n找约数 
        {
            if (n % i == 0)     //找到约数就f=0并跳出 
            {
                f = 0;
                break;
            }
        }
        if (f == 1)   //如果n为素数
        {
            ++k;                  //计数器计数 
            if (k >= 2)printf(",");  //从第2个素数起前面才加逗号
            printf("%d", n);       //后输出素数
        }
    }
    return 0;
}

使用变量k进行计数,是一个非常好用的方法和技巧,请注意要在外层循环之前进行清0操作,然后在内层循环内,如果找到素数首先立即执行++k,实现计数,并保证找到第一个素数时,k的值为1。请思考:为什么程序中先输出逗号,后输出素数,能不能先输出素数,然后再控制输出逗号呢?答案是不能的,因为我们无法得知哪一个是最后的素数,也就无法实现控制最后一个素数后不输出逗号。但是,我们可以通过给素数计数的方式,准确得知谁是第一个素数,也就可以方便地控制第一个素数前不输出逗号,而其它素数前都输出逗号。

④(代码)菱形图案

任务描述

请编程输入一个奇数n(n<100)和一个字符c,输出n行由字符c组成的菱形图案。

输入样例:

5 A

输出样例:

A

AAA

AAAAA

AAA

A

#include<stdio.h>
int main()
{
    int i, j, n, k = 1;
    char c;
    scanf("%d %c", &n, &c);
    for (i = 1;i <= n / 2 + 1;i++)  //中间和上半部分的输出
    {
        for (j = 1;j <= (n / 2 + 1) - i;j++)  //找规律输出空格
        {
            printf(" ");              //以下规律自己找,能通过就行
        }
        for (j = 1;j <= 2 * i - 1;j++)    //输出空格后输出字符
        {
            printf("%c", c);
        }
        printf("\n");
    }
    for (i = n / 2 + 2;i <= n;i++)
    {
        for (j = 1;j <= i - (n / 2 + 1);j++)
        {
            printf(" ");
        }
        for (j = (i - 2 * k) * 2 - 1;j >= 1;j--)
        {
            printf("%c", c);
        }
        k++;
        printf("\n");
    }
    return 0;
}

⑤(代码)孪生素数

任务描述

孪生素数就是指相差2的素数对,例如3和5,5和7,11和13…,已经证明孪生素数存在无穷多对。

编程输入正整数a(10000>=a>=2),输出不小于a的第一对孪生素数。差是2的两个素数被称为孪生素数。

输入样例:

10000

输出样例:

10007 10009

#include<stdio.h>
#include<math.h>
int main()
{
    int a, b, i, j;
    scanf("%d", &a);
    for (i = a;i <= 10009;i++)   //据题 最大的输出为10009
    {
        b = i + 2;
        for (j = 2;j <= sqrt(i);j++)
        {
            if (i % j == 0 || b % j == 0)
            {
                break;
            }
        }
        if (j > sqrt(i) && i != 2)  //i==2时正好跳出,但此时b==4
        {
            break;
        }
    }
    printf("%d %d", i, b);
    return 0;
}

二.处理多组数据(确定组数)

①(代码)奥运奖牌计数

任务描述

2008年北京奥运会,A国的运动员参与了n天的决赛项目(1≤n≤17)。现在要统计一下A国所获得的金、银、铜牌数目及总奖牌数。

输入格式:

输入n+1行,第1行是A国参与决赛项目的天数n,其后n行,每一行是该国某一天获得的金、银、铜牌数目,以一个空格分开。

输出格式:

输出1行,包括4个整数,为A国所获得的金、银、铜牌总数及总奖牌数,以一个空格分开。

输入样例:

3

1 0 3

3 1 0

0 3 0

输出样例:

4 4 3 11

任务分析 确定组数的多组数据

可以看出,任务要求我们处理多组数据(多组奖牌得数),数据的组数是确定的,在输入数据中最先直接给出。所以,我们可以构造一个次数固定的计次循环,在循环体内处理每组数据。问题逻辑变得相对简单。

代码:

#include<stdio.h>
int main()
{
    int n, a, b, c, i;
    int sum_a, sum_b, sum_c, sum;
    sum_a = sum_b = sum_c = 0;        //金银铜牌数量清0 
    scanf("%d", &n);             //首先读入数据组数n 
    for (i = 1;i <= n;i++)     //构造n次循环处理每组数据
    {
        //处理每组数据,读入、统计累加 
        scanf("%d%d%d", &a, &b, &c);//读入一组数据 
        sum_a += a;                //分别统计 
        sum_b += b;
        sum_c += c;
    }
    sum = sum_a + sum_b + sum_c;      //统计总数 
    printf("%d %d %d %d", sum_a, sum_b, sum_c, sum); //输出结果 
    return 0;
}

代码分析

代码首先读入数据组数n,然后通过for(i=1;i<=n;i++){ }结构实现一个n次的计次循环结构,以处理接下来的n组数据。在循环体内,循环一次就处理一组数据,内容包括首先读取金银铜牌三个整数(a,b,c),然后分别累加到三个变量(sum_a,aum_b,aum_c)中。循环结束后,统计奖牌总数,然后输出结果。

②(代码)水仙花数

任务描述

请判断一个数是不是水仙花数。水仙花数是指各个数字立方和等于它本身的三位数。

输入格式:

有多组测试数据,每组测试数据以包含一个整数n(100<=n<1000)输入0表示程序输入结束。

输出格式:

如果n是水仙花数就输出Yes否则输出No

解法1:

#include<stdio.h>
int main() 
{
    int n, i, a, b, c;
    while (1)     //每次循环处理一组数据
    {
        scanf("%d", &n);  //读入一组数据 
        if (n == 0) break;  //读入特定值跳出循环
        //处理这一组数据 
        a = n / 100;                   //提取百位数字 
        b = n % 100 / 10;                //提取十位数字 
        c = n % 10;                    //提取个位数字 
        if (n == a * a * a + b * b * b + c * c * c) //满足条件 
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}

水仙花数的判别我们已经在前一章的“水中仙子”任务中掌握了,基本思想是抽取变量n的百位数、十位数和个位数,赋值给变量“a,b,c”,然后再判断各位数字立方和是否与n相等。和任务1的解法2一样,这里我们也可以设计一种循环结构,在循环入口处(while后的括号内)完成“输入一组数据n”和“判断n是否为0”两件事。

解法2:

#include<stdio.h>
int main() 
{
    int n, i;
    int a, b, c;
    while (scanf("%d", &n), n != 0)    //读入整数n,遇0停止循环
    {
        a = n / 100;                   //提取百位数字 
        b = n % 100 / 10;                //提取十位数字 
        c = n % 10;                    //提取个位数字 
        if (n == a * a * a + b * b * b + c * c * c) //满足水仙花数条件
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}

③(代码)输出数字字符的和

任务描述

编程输入一串字符(以#字符结束),输出这串字符中所有数字字符的和。

输入样例:

ABC123DE4FG#

输出样例:

10

#include <stdio.h>
int main()
{
    int r = 0;
    char x;
    do 
    {
        scanf("%c", &x);
        if (x >= '0' && x <= '9')
        {
            r += (x - 48);  //0的ASCIIs是48
        }
    } while (x != '#');
    printf("%d", r);
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GR鲸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值