题目描述:求500万以内的亲合数
一:亲合数概念
如果两个数a和b, a的所有真因子之和等于b,b的所有真因子之和等于a,则称a,b是一对亲和数。
例如220和284:
220的真因子是:1、2、4、5、10、11、20、22、44、55、110;
284的真因子是:1、2、4、71、142。
以sum[i]表示i的所有真因子之和,所以:
sum[220] = 1+2+4+5+10+11+20+22+44+55+110= 284
sum[284] =1+2+4+71+142 = 220
二:思路
考虑用sum[i]表示i的所有真因子之和,所以sum为5000000大小的数组。所以该题的关键就是求解sum数组。
如果考虑某个数i有哪些因子,则比较复杂,可以反过来考虑,对于i来说,哪些数是它的倍数?i的倍数有2*i, 3*i, ..., x*i。所有这些数的因子中都包含i。单纯用语言不好描述,直接看代码。
三:代码
#define MaxNum 5000000
int*sum = NULL;
inti, j;
sum= malloc((MaxNum+10) * sizeof(int));
//因为1是所有数的因子,所以,首先初始化sum数组的元素为1.
for(i= 1; i <= MaxNum; i++)
{
sum[i]= 1;
}
//i表示各个因子,从2开始,一直到(MaxNum/2)为止,因为MaxNum以内的数,不可能具有因子超过(MaxNum/2)的。对于数x,如果它具有因子y,则是x = dy,如果y != x,则最大因子y,是在d=2的时候取得的。
for(i= 2; 2*i <= MaxNum; i++)
{
// j表示所有i的倍数,因为i本身不能算作真因子,所以,
//从2*i开始,一直到x*i <= MaxNum为止。
j= 2*i;
while(j<= MaxNum)
{
sum[j]+= i; //将i加到相应的sum[j]上,因为i是j的因子
j+= i; //j相应的由n*i,变为(n+1)*i
}
}
//开始扫描sum数组,求得亲合数
for(i= 1; i <= MaxNum; i++)
{
//这个条件是为了防止重复,比如出现了220 284,就不能再次出现284 220
//同时避免出现i=sum[i]这样的数,比如6,这样的数称为完全数,不是亲合数
if(i< sum[i])
{
if(sum[i]< MaxNum) //这是为了防止数组越界,参考下面的判断条件
{
if(sum[sum[i]]== i)
{
printf("%d%d ", i, sum[i]);
}
}
}
}
(http://blog.csdn.net/v_JULY_v/article/details/6441279)