project euler 110

Diophantine reciprocals II

In the following equation x, y, and n are positive integers.

1x+1y=1n

For n = 4 there are exactly three distinct solutions:

15+120=14
16+112=14
18+18=14

It can be verified that when n = 1260 there are 113 distinct solutions and this is the least value of n for which the total number of distinct solutions exceeds one hundred.

What is the least value of n for which the number of distinct solutions exceeds four million?

NOTE: This problem is a much more difficult version of Problem 108 and as it is well beyond the limitations of a brute force approach it requires a clever implementation.


丢番图倒数II

在如下方程中,x、y、n均为正整数。

1x+1y=1n

对于n = 4,上述方程恰好有3个不同的解:

15+120=14
16+112=14
18+18=14

可以验证当n = 1260时,恰好有113种不同的解,这也是不同的解的总数超过一百种的最小n值。

不同的解的总数超过四百万种的最小n值是多少?

注意:这是第108题一个极其困难的版本,而且远远超过暴力解法的能力范围,因此需要更加聪明的手段。


package projecteuler;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;

public class Prj110 extends TestCase {

	public static int LIMIT = 4 * 1000000;
	BigInteger min = null;
	DivisorsEnum div = null;

	/**
	 * n < x <= y; x = ny / ( y -n) <= y ===> y >= 2n; so assume x in (n, 2n];
	 * n(n +i)/i, i in [1, n] ===> numOfDivisors( n * n ) + 1 > 2 * LIMIT;
	 */
	public void testDiophantineReciprocalsII() {

		int count = 0;
		int mul = 1;
		while (mul < LIMIT * 2 - 1) {
			mul *= 3;
			count++;

		}
		System.out.println("count=" + (count));

		List<Integer> ls = new ArrayList<Integer>();
		for (int i = 2; i <= 100; i++) {
			if (isPrime(i)) {
				ls.add(i);
			}
		}

		BigInteger b = BigInteger.ONE;

		int[] primesArr = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
				37, 41, 43, 47 };

		for (int i = 0; i < primesArr.length; i++) {
			b = b.multiply(new BigInteger(Integer.toString(primesArr[i])));
		}
		System.out.println(b.toString());
		min = b;

		// int[] primesArr = new int[] { 2, 3, 5, 7, 11, 13, 17, 19};
		// int[] primesArr = new int[] { 2, 3, 5, 7, 11, 13, 17};
		int[] expArrs = new int[15];

		dfs(primesArr, expArrs, 0);

		System.out.println(min);
		System.out.println(div.innerCaln());
		System.out.println(div);
	}

	public static class DivisorsEnum implements Comparable<DivisorsEnum> {

		public int[] primesArr;
		public int[] expArrs;

		public DivisorsEnum(int[] primesArr, int[] expArrs) {
			super();
			this.primesArr = primesArr;
			this.expArrs = expArrs;
		}

		@Override
		public String toString() {
			return "DivisorsEnum [primesArr=" + Arrays.toString(primesArr)
					+ ", expArrs=" + Arrays.toString(expArrs) + "]";
		}

		public static BigInteger caln(int[] primesArr, int[] expArrs) {
			BigInteger n = BigInteger.ONE;
			for (int i = 0; i < expArrs.length; i++) {
				n = n.multiply(new BigInteger(Integer.toString(primesArr[i]))
						.pow(expArrs[i]));
			}
			return n;
		}

		public BigInteger innerCaln() {
			BigInteger n = BigInteger.ONE;
			for (int i = 0; i < expArrs.length; i++) {
				n = n.multiply(new BigInteger(Integer.toString(primesArr[i]))
						.pow(expArrs[i]));
			}
			return n;
		}

		@Override
		public int compareTo(DivisorsEnum o) {
			BigInteger n1 = caln(primesArr, expArrs);
			BigInteger n2 = caln(o.primesArr, o.expArrs);

			return n1.compareTo(n2);
		}
	}

	public void dfs(int[] primesArr, int[] expArrs, int startIndex) {
		if (startIndex >= expArrs.length) {
			long numOfDivisors = 1;
			for (int i = 0; i < expArrs.length; i++) {
				numOfDivisors *= (2 * expArrs[i] + 1);
			}
			if (numOfDivisors > 2 * LIMIT - 1) {
				DivisorsEnum d = new DivisorsEnum(Arrays.copyOf(primesArr,
						expArrs.length), Arrays.copyOf(expArrs, expArrs.length));
				if (d.innerCaln().compareTo(min) < 0) {
					min = d.innerCaln();
					div = d;
				}
				System.out.println(d);
			}
			return;
		}

		for (int i = 0; i <= 10; i++) {

			// guess
			if (startIndex > 5 && i >= 2) {
				return;
			}
			// exp[i] >= exp[i + 1]
			if (startIndex != 0 && i > expArrs[startIndex - 1]) {
				continue;
			}
			expArrs[startIndex] = i;

			long numOfDivisors = 1;
			for (int j = 0; j <= startIndex; j++) {
				numOfDivisors *= (2 * expArrs[j] + 1);
			}
			if (numOfDivisors > 2 * LIMIT - 1) {
				int[] copy = new int[expArrs.length];
				for (int j = 0; j <= startIndex; j++) {
					copy[j] = expArrs[j];
				}
				DivisorsEnum d = new DivisorsEnum(Arrays.copyOf(primesArr,
						expArrs.length), Arrays.copyOf(copy, copy.length));
				if (d.innerCaln().compareTo(min) < 0) {
					min = d.innerCaln();
					div = d;
				}
				System.out.println(d);
				return;
			}
			dfs(primesArr, expArrs, startIndex + 1);

		}

	}

	boolean isPrime(int num) {
		if (num <= 10) {
			if (num == 2 || num == 3 || num == 5 || num == 7) {
				return true;
			}
			return false;
		}

		if (num % 2 == 0) {
			return false;
		}

		for (int i = 3; i * i <= num; i = i + 2) {
			if (num % i == 0) {
				return false;
			}
		}
		return true;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值