求亲和数

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;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值