项目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;
}
输出
小结
- 找真因子循环条件如果写成
for (i=2;i<=n/2;i++)
漏掉n/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年)。