编程输出2-1000中所有的完全数,所谓的完全数是指整数n的所有小于n的正因数之和若等于n本身,则称数n为完全数。例如6的小于6的正因数为1,2,3。而1+2+3=6,则6是一个完全数。
这道题的解题思路就是遍历,首先你要遍历2-1000里的所有数字
for(int i=2;i<1000;i++)
接着遍历1-i中的所有数字,来找i的因子
for(int j=1;j<i;j++)
如果j是i的因子,那么他肯定能整除i或者说i%j=0
if(i%j==0)
如果j是i的因子;就把他加到因子和sum中
sum+=j;
最后,做一个判定,如果因子和sum等于i,那么i就是完全数
if(sum==i){
printf("%d是完全数\n",i);
}
下面为最简单的没优化的代码:
#include<stdio.h>
main(){
for(int i=2;i<1000;i++){//遍历2-1000的所有数字
int sum=0;
for(int j=1;j<i;j++){//遍历1+i之间的所有数字
if(i%j==0)//如果j是i的因子
sum+=j;//把就j加到和中
}
if(sum==i){//如果因子和sum与i相等,i就是完全数
printf("%d是完全数\n",i); //输出i是完全数
}
}
}
但是上面的代码我们会发现他有太多的不必要的运算,比如找因子的时候,我们没必要遍历到i,只需要遍历到√i就可以了。
因为因数都是成对出现的。比如,100的因数有:1和100,2和50,4和25,5和20,10和10。看出来没有?成对的因数,其中一个必然小于等于100的开平方,另一个大于等于100的开平方。至于严密的数学证明,用小学数学知识就可以搞定,我就不啰嗦了。
所以代码的第二个遍历就从
for(int j=1;j<i;j++)
变成了
for(int j=1;j<sqrt(i);j++)
而加的部分也由
sum+=j;
变成了
sum=sum+j+i/j;
其中j是你找到的因数,i/j是与之相对的另一个因数
这是我们会发现一个问题,比如说9这个数,开平方等于3,按上述代码的话sum=sum+3+3
3被加了两回,这个错误会出现在所有的平方数中,所以,要进行一个判定,如果这个数是完全平方数,就减去一个平方因子。
int t=sqrt(i);
if(t*t==i)
sum-=t;
如果因数和在加的过程中比i大了,我们也可以不用算后面的和了,因为肯定不是完全数了
if(sum>i)
break;
根据以上分析,得到优化的代码如下:
#include<stdio.h>
#include<math.h>
main(){
for(int i=2;i<1000;i++){//遍历2-1000的所有数字
int sum=1;
int t=sqrt(i);
if(t*t==i)sum-=t;
for(int j=2;j<=t;j++){
if(i%j==0)
sum=sum+j+i/j;
if(sum>i)
break;
}
if(sum==i){
printf("%d是完全数\n",i);
}
}
}
来源:CSDN
作者:竞仔今天也要努力码一千字
链接:https://blog.csdn.net/weixin_45911481/article/details/103700591