#39 问题求解(一)

项目1 完数

一个数如果恰好等于它的真因子之和,这个数就称为“完数”。例如6=1+2+3,再如8的因子和是7(即1+2+4),8不是完数。
(1)输入一个数n,判断n是否是完数

代码一(完数判断)
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月25日
*版 本 号:v1.0
*问题描述:判别n是否为完数(真因子之和等于本身)
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int i,j,k,n,sum,prime=1;
    printf("请输入n:");
    scanf("%d",&n);
    //判断是否素数
    k=sqrt(n);
    for (i=2;i<=k;i++)
    {
        if (n%i==0)
        {
            prime=0;
            break;
        }
    }
    if (prime==1)   //是素数就不是完数
        printf("%d不是完数",n);
    //不是素数就进行下面的计算
    else
    {
        sum=1;
        for (i=2;i<=n-1;i++)    //找真因子并求和
        {
            j=n/i;
            if (n==i*j)
            {
                sum+=j;
                continue;
            }
        }
        if (n==sum)
            printf("%d是完数",n);
        else
            printf("%d不是完数",n);
    }
    return 0;
}
输出

这里写图片描述
这里写图片描述

小结
  1. 找真因子循环条件如果写成for (i=2;i<=n/2;i++)漏掉n/2后面的因子导致出错。另如果不是素数会导致两次循环计算,计算量太大。
  2. 取消素数判断程序,寻找真因子循环优化为(减少计算量):
        for (i=2;i<sqrt(n);i++)    //利用因子对称性找真因子并求和,注意开方没有等号
        {
            if (n%i==0)
            {
                sum+=(i+n/i);   //因子成对相加
                continue;
            }
        }
        if (n==i*i)    //n是平方数时i加一次就好
            sum+=i;

(2)输出1000以内的所有完数

代码二
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月25日
*版 本 号:v1.0
*问题描述:输出1000以内的所有完数
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int i,j,sum,count=0;

    for (i=4;i<=1000;i++) //从4开始排除123

    {
        for (j=2,sum=1;j<sqrt(i);j++)    //找真因子并求和
        {
            if (i%j==0)
            {
                sum+=(j+i/j);
                continue;
            }
        }
        if (i==j*j)
            sum+=j;
        if (i==sum)
        {
            count++;
            printf("%d\t",i);
            if (count%5==0)
                printf("\n");
        }
    }
    return 0;
}
输出

这里写图片描述

(3)亲密数:如果整数A的全部因子(包括1,不包括A本身)之和等于B;且整数B的全部因子(包括1,不包括B本身)之和等于A,则将整数A和B称为亲密数。求3000以内的全部亲密数。(提示:按照亲密数定义,要判断数a是否有亲密数,只要计算出a的全部因子的累加和为b,再计算b的全部因子的累加和为n,若n等于a且不等于b则可判定a和b是亲密数。)

代码三
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月25日
*版 本 号:v1.0
*问题描述:求3000以内的全部亲密数。
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int a,i,j,k,sa,sb,count=0;
    //排除123,从4开始
    for (a=4;a<=3000;a++)

    {
        //求a的因式和sa
        for (i=2,sa=1;i<=a-1;i++)
        {
            k=a/i;
            if (a==k*i)
            {
                sa+=k;
                continue;
            }
        }
        //b=sa
        for (j=2,sb=1;j<=sa-1;j++)    //找真因子并求和
        {
            k=sa/j;
            if (sa==j*k)
            {
                sb+=k;
                continue;
            }
        }
        if (a==sb&&a!=sa)
        {
            count++;
            printf("%d\t真因子和%d\n",a,sa);
        }
    }
    return 0;
}
输出

这里写图片描述

小结

要排除掉a是完数的情况(a=b),另外真因子求和可以用前面的方法优化计算

项目2 n=a!+b!+c!

求满足条件n=a!+b!+c!的所有三位数n并输出,其中a,b,c分别为n的百、十、个位数。

代码
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月25日
*版 本 号:v1.0
*问题描述:求满足条件n=a!+b!+c!的所有三位数n并输出,其中a,b,c分别
*为n的百、十、个位数。
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int n,i,a,b,c,fa,fb,fc,count;
    for (n=100;n<=999;n++)
    {
        a=n/100;
        b=(n/10)%10;
        c=n%10;
        for (i=1,fa=1;i<=a;i++)
            fa*=i;
        for (i=1,fb=1;i<=b;i++)
            fb*=i;
        for (i=1,fc=1;i<=c;i++)
            fc*=i;
        if (n==fa+fb+fc)
        {
            printf("%d\t",n);
            count++;
            if (count%5==0)
                printf("\n");
        }
    }
    return 0;
}
输出

这里写图片描述

小结

三个循环不能合并但如果函数体太多时可新建一个C文件装函数然后调用。

项目3 反序数

(1)输入一个正整数,输出它的反序数(反序数,即将其所有位的数字反过来。例如,123是321的反序数)

代码
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月26日
*版 本 号:v1.0
*问题描述:输入一个正整数,输出它的反序数
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int n,m,i;
    printf("输入n:");
    scanf("%d",&n);
    for (i=n,m=0;i>0;i/=10) //当n为一位数时十位上是0,故初值m=0
        m=10*m+i%10;
    printf("%d的反序数为%d",n,m);
    return 0;
}
输出

这里写图片描述
这里写图片描述
(2)求1000000以内的正整数n,要求9n是n的反序数。

代码
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月26日
*版 本 号:v1.0
*问题描述:求1000000以内的正整数n,要求9n是n的反序数
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int n,m,i;
    for (n=9;n<1e6;n+=9)    //n一定是9的倍数
    {
        for (i=n,m=0;i>0;i/=10) //当n为一位数时十位上是0,故初值m=0
            m=10*m+i%10;
        if (9*n==m)
            printf("n=%d反序数为%d\n",n,9*n);
    }
    return 0;
}
输出

这里写图片描述

小结

由于n和9n都在(0,1e6)区间内且9n反序数为n,所以n一定是9的倍数,认识这点可以节省计算量。

项目4 回文数

(1)输入一个正整数,判断其是否为一个回文数(例1221、12321都是回文数,正着看、倒着看,是同一个数)。

代码
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月26日
*版 本 号:v1.0
*问题描述:输入一个正整数,判断其是否为一个回文数
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int n,m,i;
    printf("输入n:");
    scanf("%d",&n);
    //如果正整数的反序数就是它本身,它就是回文数
    for (i=n,m=0; i>0; i/=10)
        m=m*10+i%10;
    if (m==n)
        printf("YES!",n);
    else
        printf("NO!");
    return 0;
}
输出

这里写图片描述
这里写图片描述

(2)输出10000以内的所有回文数。

代码
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月26日
*版 本 号:v1.0
*问题描述:输出10000以内的所有回文数
*/
#include <stdio.h>
#include <math.h>
int main()
{
    int n,m,i,count=0;
    for (n=1; n<1e4; n++)
    {
        for (i=n,m=0; i>0; i/=10)
            m=m*10+i%10;
        if (m==n)
        {
            count++;
            printf("%-4d ",n);
            if (count%10==0)
                printf("\n");
        }
    }

    return 0;
}
输出

这里写图片描述

小结

回文数就是满足反序数是它本身的数。

项目5 阿姆斯特朗数

如果一个正整数等于其各个数字的立方和,则称该数为阿姆斯特朗数(亦称为自恋性数)。如 407=4^3+0^3+7^3就是一个阿姆斯特朗数。试编程求1000以内的所有阿姆斯特朗数。

/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月26日
*版 本 号:v1.0
*问题描述:编程求1000以内的所有阿姆斯特朗数
*/
#include <stdio.h>
int main()
{
    int n,i,m,sum;
    for (n=1; n<1000; n++)
    {
        i=n;
        sum=0;
        while (i>0)
        {
            m=i%10;
            sum+=m*m*m;
            i=i/10;
        }
        if (sum==n)
        {
            printf("%d ",n);
        }
    }
    return 0;
}
输出

这里写图片描述

小结

求一个数的每一位就用它不断地对10取余即可。

项目6 回文日

很有趣的一个题目:2011年11月02日是一个回文日:2011 1102,在2011级同学做这道题时我们刚刚度过这一天!请列出本世纪还有多少个回文日(假如我们能活到百岁,你和我的……)。注意:一年只有12个月。

代码
/**
*Copyright @2018,CSDN学院
*All rights reserved.
*文件名称:main.c
*作    者:袁生
*完成日期:2018年1月26日
*版 本 号:v1.0
*问题描述:请列出本世纪还有多少个回文日
*/
#include <stdio.h>
int main()
{
    int year,month,count=0;
    //本世纪只剩下2012~2099,所以本世纪回文日一定是02日
    //从月份分析排除01月(10年)10月(01年)11月(11年),剩下2~9月和12月
    //2~9月每过一月对应过10年,12月单独计算(只对应2021年)
    for (year=20; year<100; year+=10)
    {
        for (month=2; month<=9; month++)
        {
            if (year/10==month)
            {
                printf("20%d年%d月02日\n",year,month);
                count++;
            }
        }
    }
    count++;    //加上12月对应的2021年
    printf("2021年12月02日\n");
    printf("本世纪共计还有%d个回文日",count);
    return 0;
}
输出

这里写图片描述

小结

分析题意提炼计算:
1. 本世纪只剩下2012~2099,所以本世纪回文日一定是02日;
2. 从月份分析排除01月(对应2010年已过)10月(对应2001年)11月(对应2011年),剩下2~9月和12月;
3. 2~9月每过一月对应过10年,12月单独计算(只对应2021年)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值