第39课 问题求解——求素数
项目一【完数】
一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3,再如8的因子和是7(即1+2+4),8不是完数。
(1)输入一个数n,判断n是否是完数
(2)输出1000以内的所有完数
(3)亲密数:如果整数A的全部因子(包括1,不包括A本身)之和等于B;且整数B的全部因子(包括1,不包括B本身)之和等于A,则将整数A和B称为亲密数。求3000以内的全部亲密数。(提示:按照亲密数定义,要判断数a是否有亲密数,只要计算出a的全部因子的累加和为b,再计算b的全部因子的累加和为n,若n等于a则可判定a和b是亲密数。)
(1)输入一个数n,判断n是否是完数
(2)输出1000以内的所有完数
(3)亲密数:如果整数A的全部因子(包括1,不包括A本身)之和等于B;且整数B的全部因子(包括1,不包括B本身)之和等于A,则将整数A和B称为亲密数。求3000以内的全部亲密数。(提示:按照亲密数定义,要判断数a是否有亲密数,只要计算出a的全部因子的累加和为b,再计算b的全部因子的累加和为n,若n等于a则可判定a和b是亲密数。)
(1)代码:
自己摸索的做的,可循环输入,效率较低
/*
39课-循环-求完数-项目1.1
2015.12.25
BenjaVan
*/
#include<stdio.h>
int main()
{
int i,num,sum;
char c;
printf(" * 完数计算 *\n");
do//可循环使用计算程序
{
i=1; //赋初值
sum=0; //赋初值
printf("请输入数字:");
scanf("%d",&num);
printf("因子:");
while(i<=(num-1)) //循环计算完数的因子
{
if(num%i==0) //如果余数为零,则i是其因子
{
printf("%d ",i);
sum=sum+i; //把因子累加
}
i++;
}
printf(" 和:%d\n",sum);
if(sum==num) //分支显示此数是否为完数
printf("%d是完数!\n",num);
else
printf("%d不是完数!\n",num);
printf("* 按N键退出程序,任意键继续 * "); //退出程序的出口
fflush(stdin); //清空缓冲区
scanf("%c",&c);
if(c=='n'||c=='N')
break;
printf("\n");
}
while(1); //可以再次输入数字,计算是否为完数的大循环
printf("\n--程序已结束--\n");
return 0;
}
运行结果:
做了一遍老师的代码:
学习其中更效率的算法
#include<stdio.h>
#include<math.h>
int main()
{
int i,sum=1,num;
printf("请输入:");
scanf("%d",&num);
for(i=2;i<sqrt(num);i++)
if(num%i==0)
sum+=(i+num/i);
if(i*i==num)
num+=i;
printf("因子和为:%d\n",sum);
if(num==sum)
printf("%d是完数\n",num);
else
printf("%d不是完数\n",num);
return 0;
}
(2)代码:
/*
39课-循环-求完数-项目1.2
2015.12.25
BenjaVan
*/
#include<stdio.h>
#include<math.h>
int main()
{
int num,j,sum,n=1000;
printf("1-%d之间的完数有:\n",n);
for(num=2;num<=n;num++)
{
sum=1;
j=2;
do
{
if(num%j==0)
sum+=(j+num/j);
j++;
}
while(j<sqrt(num));
if(j*j==num)
sum=sum+j;
if(sum==num)
printf("%d ",num);
}
printf("\n");
return 0;
}
运行结果:
(3)代码:
#include<stdio.h>
int main()
{
int i,a,b,n;
for(a=1;a<=3000;a++)
{
b=0;
n=0;
for(i=1;i<=(a-1);i++)
if(a%i==0)
b=b+i;
for(i=1;i<=(b-1);i++)
if(b%i==0)
n=n+i;
if(n==a&&a!=b)
printf("%d-%d\n",a,b);
}
return 0;
}
运行结果:
————————————————————————————————————————————————————————————————————
项目二【 n=a!+b!+c!】
求满足条件n=a!+b!+c!的所有三位数n并输出,其中a,b,c分别为n的百、十、个位数。
代码:
这个题因为考虑了一些效率方面的问题,人为在程序上做了改变,但算法变复杂了,出错的可能性更大了。 — —任何的工程,遵循“简单即是美”的法则
在检测程序运行没问题后,将它记录了下来
#include<stdio.h>
int main()
{
int i,a1,a2,b1,b2,c1,c2,num;
for(num=100;num<556;num++) //556以上没有计算意义
{
a2=1;
b2=1; //不受0的影响,0的阶乘为1
c2=1;
c1=num%10;
b1=(num/10)%10;
a1=(num/100)%10;
if(b1>=6||c1>=6) //大于等于6时跳过
{
num+=3;
continue;
}
for(i=1;i<=a1;i++) //计算阶乘
a2*=i;
for(i=1;i<=b1;i++)
b2*=i;
for(i=1;i<=c1;i++)
c2*=i;
if((a2+b2+c2)==num)
printf("%d\n",num);
}
return 0;
}
运行结果:
————————————————————————————————————————————————————————————————————
项目三【反序数】
(1)输入一个正整数,输出它的反序数(反序数,即将其所有位的数字反过来。例如,123是321的反序数)
(2)求1000000以内的正整数n,要求9n是n的反序数。
(2)求1000000以内的正整数n,要求9n是n的反序数。
做这道题时真的写了好久,从一开始看到题目时感觉挺简单,跟着脑子里的思路走,但发现所学到的知识完全不知道怎么把一个随机数字的位数解决,差点就放弃了,试了很多次之后才走向了 /10 的方向,我先计算了数字的位数,然后分离各个数,再根据位数累加成反序数,过程太昂乱,必然是比不上老师的参考答案,不过能通过自己努力做出来确实很开心了,我想价值在这个坚持求解的过程,好过直接学一个解决方案,所以把这个笨解保留了下来,留念一下: )
(1)代码:
#include<stdio.h>
int main()
{
int i=1,j,n,t,k,num,num2,a,sum=0;
scanf("%d",&num);
num2=num;
for(i=0;num2!=0;i++)
num2=num2/10;
j=1;
k=i;
while(j<=i)
{
t=1;
a=num%10;
for(n=1;n<=(k-1);n++)
t=t*10;
sum=sum+a*t;
num=(num-a)/10;
j++;
k--;
}
printf("%d",sum);
return 0;
}
运行结果:
学习老师的算法:
真的太巧妙了,赞啊
#include<stdio.h>
int main()
{
int i=1,num1,num2=0;
scanf("%d",&num1);
i=num1;
while(i!=0)
{
num2=num2*10+i%10; //新数通过乘10来让位,加上原来数的个位数,循环做这个
i=i/10; //以原来数的位数确定循环的次数,并缩小位数
}
printf("%d\n",num2);
return 0;
}
(2)代码:
#include <stdio.h>
int main()
{
int n,m,k;
for(n=1; n<1000000; n++)
{
k=n;
m=0; //m将为n的反序数
while(k>0)
{
m=m*10+k%10;
k=k/10;
}
if(m==9*n) //n的反序数m等于9n
printf("%d--%d\n",n,m);
}
printf("\n");
return 0;
}
运行结果:
————————————————————————————————————————————————————————————————————
项目四【回文数】
(1)输入一个正整数,判断其是否为一个回文数(例1221、12321都是回文数,正着看、倒着看,是同一个数)。
(2)输出10000以内的所有回文数。
(2)输出10000以内的所有回文数。
(1)有了前面的基础,可以在此基础上来解题
代码:
#include<stdio.h>
int main()
{
int i,num1,num2;
char c;
do
{
printf("请输入:");
scanf("%d",&num1);
i=num1;
num2=0;
while(i!=0)
{
num2=num2*10+i%10;
i=i/10;
}
if(num2==num1)
printf(" 是回文数");
else
printf(" 不是哦");
printf("(按N键退出,其他键退出) ");
fflush(stdin);
c=getchar();
if(c=='N'||c=='n')
{
printf("\n已退出\n");
break;
}
printf("\n");
}
while(1);
return 0;
}
运行结果:
(2)一共两种方法,一种用反序数的原理,一种直接组成符合回文的数然后输出
代码1:
#include<stdio.h>
int main()
{
int i,k=1,num1,num2;
for(num1=1;num1<=10000;num1++)
{
num2=0;
i=num1;
while(i!=0)//计算原数的反序数
{
num2=num2*10+i%10;
i=i/10;
}
if(num1==num2)//原数与其反序数相等则是回文数
{
printf("%d ",num2);
if(k%10==0)//10个一行:)
printf("\n");
k++;
}
}
printf("\n");
return 0;
}
运行结果:
代码2:
#include<stdio.h>
int main()
{
int m,n;
for(m=1;m<=9;++m)//一位数的
printf("%d ",m);
printf("\n");//十个换行
for(m=1;m<=9;++m)//两位数的
printf("%d ",m*10+m);
printf("\n");//十个换行
for(m=1;m<=9;++m)//三位数
{
for(n=0;n<=9;++n)
printf("%d ",m*100+n*10+m);
printf("\n");//十个换行
}
for(m=1;m<=9;++m)//四位数
{
for(n=0;n<=9;++n)
printf("%d ",m*1000+m+n*100+n*10);
printf("\n");//十个换行
}
return 0;
}
运行结果:
————————————————————————————————————————————————————————————————————
项目五【阿姆斯特朗数】
如果一个正整数等于其各个数字的立方和,则称该数为阿姆斯特朗数(亦称为自恋性数)。如 407=43+03+73就是一个阿姆斯特朗数。试编程求1000以内的所有阿姆斯特朗数。
代码:
#include<stdio.h>
int main()
{
int num,a,b,c;
printf("1000内的阿姆斯特朗数:\n");
for(num=1;num<=955;++num)//996的立方和已经大于1000,不再计算了
{
c=num%10;
b=(num/10)%10;
a=num/100;
a=a*a*a;//简单的求立方
b=b*b*b;
c=c*c*c;
if(num==(a+b+c))
printf("%d ",num);
}
printf("\n");
return 0;
}
运行结果:
————————————————————————————————————————————————————————————————————
项目六【回文日】
很有趣的一个题目:2011年11月02日是一个回文日:2011 1102,在2011级同学做这道题时我们刚刚度过这一天!请列出本世纪还有多少个回文日(假如我们能活到百岁,你和我的……)。注意:一年只有12个月。
代码1:
因为问题所求的是本世纪,所以2000年的回文是0002(2100年的回文数是0012,没有0月这一说,所以只算到2090年就行),也就是说,只有每年每月2号才可能是回文日,所以做了简单的算法,虽然不会出错,但是不严谨
#include<stdio.h>
int main()
{
int year,moon,day,n;
for(year=0;year<=90;++year)//90年足够
{
for(moon=1;moon<=12;++moon) //每月都循环,其实只有月份才是变化回文日的关键数
{
day=2+moon*100; //只有每月2日能构成回文
n=2000+(moon%10)*10+moon/10; //做一个反序数,加上大的年份
if(n==(year+2000))
printf("%d-%04d\n",year+2000,day);
}
}
return 0;
}
其中可以直接去掉年份的循环,更简略的代码如下:
#include<stdio.h>
int main()
{
int month;
for(month=1;month<=12;++month)
printf("%d-%04d\n",2000+(month%10)*10+month/10,2+month*100);
return 0;
}