问题描述:
两个数彼此的全部约数和(本身除外)都与另一方相等。例如220和284:
220的全部约数(除了220)相加是:
1+2+4+5+10+11+20+22+44+55+110=284
同样284的全部约数(除了284)相加是:
1+2+4+71+142=220
算法关键:
1:如何求一个数N的全部约数?
- 可知N%约数 == 0;
2:每个数的约数和如何存储,各个和之间如何比较?
创建一个数组S[30000],每产生一个约数和sum就放入数组中
(数组下标代表着数,里面存的值为该数的约数和,如S[220] = 284,
S[284]=220)
long S[30000];
int sum = 0;
for(int j = 1;j<=30000;j++){
for(int i = 1;i<j;i++){//注意不包括这个数本身所以i不能等于j
if(!j%i) S[i]+=i;
}} //将各个数的约数和sum存进S[];
3:再对数组S中的数进行遍历比较,找出相同的值。判别是否为相亲数条件:
S[h] ==m) && (S[m] ==h
for(int m =2;m<=30000;m++){
for (int h =m+1;h<=30000;h++){
if((S[h] ==m) && (S[m] ==h)) printf("%d,%d",h,m);
源代码:
结果:
分析:该算法需要用到的数组很大,且时间复杂度很高0(n^2)。
算法改进:从几方面:
1:求约数和的算法:
观察一个数的所有约数排列如(1 2 4 5 10 11 20 22 44 55 110 220)我们发现是对称的,右边的等于220除以左边的。则算法可以改进为如下图,我们将i的循环条件改为i<根号N。
时间复杂度由0(n2)变为0(n1.5)。
时间复杂度为0[n]的算法:
算法思想是先不急着把1到30000的每个数的约数都求出来并存在数组中。而是遍历一遍,算出一个数i的约数和S[i],再算数S[i]的和S[S[i]].然后比较i和S[S[i]]是否相等来判断是否为一对相亲数。
运行结果: