设正整数a的小于其本身的真因数之和为s,定义 p(a)=s/a 为整数a的因数比;
事实上,完全数是因数比为1的整数。例如 p(6)=1 ,6为完全数;
若整数的因数比为某一大于1的整数p,则称该整数为p-完全数。例如p(120)=2,则120为 2-完全数;
试搜索指定区间 [x,y] 中的完全数与 p-完全数。若区间中没有完全数与 p-完全数,探求区间中哪一个整数的因数比最接近某一正整数;
1.说明:
为了求整数a的真因数和s,设置 k(2~sqrt(a))循环枚举,如果k是a的因数,则a/k也是a的因数,通过迭代 s=s+k+a/k,求取因数和 s;
如果a=b*b,显然k=b,a/k=b,此时k=a/k,而因数b只有一个,所以此时必须从和s中减去一个b,这样避免重复计算的处理是必要的;
*设置min存储因数比与正整数差值的最小值,通过计算s,t=s/a及与正整数d的最小差距c=t-d(c>=0):
- 若c=0,此时的因数比t为正整数,通过数组p、q存储a及其因数比;
- 若c>0,通过与min比较求取因数比最接近正整数d;
2.程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
double a,a1,s,b,c,d,d1,k,t,t1,x,y,p[10],q[10],min;
int j,m=0;
min=1.0;
printf("请输入区间x,y:");
scanf("%d,%d",&x,&y);
for(a=x;a<=y;a++) /*枚举区间内所有的整数a*/
{
s=1;
b=floor(sqrt(a));
for(k=2;k<=b;k++) /*试商寻求a的因数k*/
if(fmod(a,k)==0)
s=s+k+a/k; /*k与a/k都是a的因数,求和*/
if(a==b*b)
s=s-b; /*如果a=b²,去掉重复因数b*/
t=s/a;
d=floor(t);
c=t-d;
if(c==0)
{
m++;
p[m]=a;
q[m]=t;
}
else if(c>0.5)
{
c=1-c;
d=d+1;
}
if(t>0.5&&c<min) /*比较求因数比最接近的整数*/
{
min=c;
a1=a;
t1=t;
d1=d;
}
}
if(m>0)
for(j=1;j<=m;j++) /*逐一输出p-完全数*/
printf(" p(%.0f)=%.0f",p[j],q[j]);
else
printf(" %.0f的因数比%.4f最接近正整数%.0f。\n",a1,t1,d1);
}
3.程序运行示例及其注意事项:
请输入区间x,y:100,10000
p(120)=2 p(496)=1 p(672)=2 p(8128)=1
请输入区间x,y:10000,20000
16384的因数比0.9999最接近正整数1。
注意:设参数y的数量级为n,双重循环的运算量为 n^(3/2),即算法的时间复杂度为 O(n^(3/2))
由程序还可以得因数比为3的3-完全数,如p(30240)=3,p(32760)=3;
改进程序还可以探求到因数比为4的4-完全数,如p(518666803200)=4;
那么,是否存在5-完全数或6-完全数?