package com.refe.algorithm;
import org.junit.Test;
/*
* 求500万以内的所有亲和数
* 如果两个数a和b,a的所有真因数之和等于b,b的所有真因数之和等于a,则称a,b是一对亲和数。
* 例如220和284,1184和1210,2620和2924。
*
* 然后取i=2,3,4,5(i<=10/2),j依次对应的位置为j=(4、6、8、10),(6、9),(8),(10)各数所对应的位置。
* 依据j所找到的位置,在j所指的各个数的下面加上各个真因子i(i=2、3、4、5)。
* 整个过程,即如下图所示(如sum[6]=1+2+3=6,sum[10]=1+2+5=8.):
* 1 2 3 4 5 6 7 8 9 10
* 1 1 1 1 1 1 1 1 1 1
* 2 2 2 2
* 3 3
* 4
* 5
* 然后一次遍历i从220开始到5000000,i每遍历一个数后,
* 将i对应的数下面的各个真因子加起来得到一个和sum[i],如果这个和sum[i]==某个i’,且sum[i‘]=i,
* 那么这两个数i和i’,即为一对亲和数。
* i=2;sum[4]+=2,sum[6]+=2,sum[8]+=2,sum[10]+=2,sum[12]+=2...
* i=3,sum[6]+=3,sum[9]+=3...
* ......
* i=220时,sum[220]=284,i=284时,sum[284]=220;即sum[220]=sum[sum[284]]=284,
* 得出220与284是一对亲和数。所以,最终输出220、284,...
* */
public class Amicablenumbers {
@Test
public void test() {
amicable();
}
final private static int LENGTH = 5000000;
private int[] array = new int[LENGTH];
private void amicable() {
init();// 初始化伴随数组
getcompany();// 遍历数组,求伴随数组
getamicable();// 取伴随数组 array[j]=i 同时array[i]=j; 即array[array[i]]==i;
}
private void getamicable() {
for (int i = 0; i < LENGTH; i++)
if (array[i] > i && array[i] < LENGTH && array[array[i]] == i)
// 去重及自身,防止越界,求亲和数
System.out.println(i + "," + array[i]);
}
private void getcompany() {
for (int i = 2; (i << 1) < LENGTH; i++) {// 一个数的真因数不大于其1/2
int j = (i << 1);// 一个数本身不是真因数,因此从其2倍开始
while (j < LENGTH) {
array[j] += i;// 对应位置伴随数组加上真因数
j += i;// 寻找下一个
}
}
}
private void init() {
for (int i = 0; i < LENGTH; i++)
array[i] = 1;
}
}
求亲和数
最新推荐文章于 2023-11-29 17:13:39 发布