project euler 88

Problem 88


Product-sum numbers

A natural number, N, that can be written as the sum and product of a given set of at least two natural numbers, {a1, a2, … , ak} is called a product-sum number: N = a1 + a2 + … + ak = a1 × a2 × … × ak.

For example, 6 = 1 + 2 + 3 = 1 × 2 × 3.

For a given set of size, k, we shall call the smallest N with this property a minimal product-sum number. The minimal product-sum numbers for sets of size, k = 2, 3, 4, 5, and 6 are as follows.

k=2: 4 = 2 × 2 = 2 + 2
k=3: 6 = 1 × 2 × 3 = 1 + 2 + 3
k=4: 8 = 1 × 1 × 2 × 4 = 1 + 1 + 2 + 4
k=5: 8 = 1 × 1 × 2 × 2 × 2 = 1 + 1 + 2 + 2 + 2
k=6: 12 = 1 × 1 × 1 × 1 × 2 × 6 = 1 + 1 + 1 + 1 + 2 + 6

Hence for 2≤k≤6, the sum of all the minimal product-sum numbers is 4+6+8+12 = 30; note that 8 is only counted once in the sum.

In fact, as the complete set of minimal product-sum numbers for 2≤k≤12 is {4, 6, 8, 12, 15, 16}, the sum is 61.

What is the sum of all the minimal product-sum numbers for 2≤k≤12000?


积和数

若自然数N能够同时表示成一组至少两个自然数{a1, a2, … , ak}的积和和,也即N = a1 + a2 + … + ak = a1 × a2 × … × ak,则N被称为积和数。

例如,6是积和数,因为6 = 1 + 2 + 3 = 1 × 2 × 3。

给定集合的规模k,我们称满足上述性质的最小N值为最小积和数。当k = 2、3、4、5、6时,最小积和数如下所示:

k=2: 4 = 2 × 2 = 2 + 2
k=3: 6 = 1 × 2 × 3 = 1 + 2 + 3
k=4: 8 = 1 × 1 × 2 × 4 = 1 + 1 + 2 + 4
k=5: 8 = 1 × 1 × 2 × 2 × 2 = 1 + 1 + 2 + 2 + 2
k=6: 12 = 1 × 1 × 1 × 1 × 2 × 6 = 1 + 1 + 1 + 1 + 2 + 6

因此,对于2≤k≤6,所有的最小积和数的和为4+6+8+12 = 30;注意8只被计算了一次。

已知对于2≤k≤12,所有最小积和数构成的集合是{4, 6, 8, 12, 15, 16},这些数的和是61。

对于2≤k≤12000,所有最小积和数的和是多少?

package projecteuler;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import junit.framework.TestCase;

public class Prj88 extends TestCase {

	static final int LIMIT = 12000;
	static int[] ts = new int[LIMIT];

	public void testProductSumNumbers() {

		Set<Integer> set = new HashSet<Integer>();
		for (int k = 2; k <= LIMIT; k++) {
			for (int num = k; num <= 2 * k; num++) {
				if (dfs(0, 2, num, k, num, ts)) {
					if (k % 1000 == 0) {
						String fstr = "k=%d,num=%d";
						fstr = String.format(fstr, k, num);
						System.out.println(fstr);
					}
					set.add(num);
					break;
				}
			}
		}

		int sum = 0;
		for( int val : set){
			sum += val;
		}
		
		System.out.println("sum=" + sum);

	}

	public boolean dfs(int depth, int maxDivisor, int num, int k, int rest,
			int[] ts) {

		assert (ts.length == k);
		// 边界
		if (depth > k - 1) {
			return false;
		}

		// 检查是否可提前返回
		if (depth > 0) {
			int tmp = 0;
			int mul = 1;
			for (int i = 0; i < depth; i++) {
				tmp += ts[i];
				mul *= ts[i];
			}
			assert (ts[depth] <= (num / mul));

			if (tmp + (k - depth - 1) + num / mul == num) {
				ts[depth] = num / tmp;
				printResult(ts, k, depth, num, false);
				return true;
			}
		}

		List<Integer> divisors = getDivisors(rest, maxDivisor);

		for (int i = 0; i < divisors.size(); i++) {
			int div = divisors.get(i);
			// 保证因子递增且剩下的余积不小于当前最大因子
			if (rest / div < div) {
				continue;
			}
			ts[depth] = div;
			if (dfs(depth + 1, div, num, k, rest / div, ts)) {
				return true;
			}
			// no need to reset; a depth flag is enough
		}

		return false;
	}

	void printResult(int[] idx, int K, int numOfDiv, int num, boolean print) {
		if (!print) {
			return;
		}
		for (int i = 0; i < idx.length; i++) {
			if (i != idx.length - 1) {
				if (i <= numOfDiv) {
					System.out.print(idx[i] + "+");
				} else {
					System.out.print(1 + "+");
				}
			} else {
				if (i <= numOfDiv) {
					System.out.print(idx[i] + "=");
				} else {
					System.out.print(1 + "=");
				}
			}
		}
		System.out.println(num);
	}

	List<Integer> getDivisors(int num, int start) {
		List<Integer> ret = new ArrayList<Integer>();

		assert (start <= num);
		for (int i = start; i < num; i++) {
			if (num % i == 0) {
				ret.add(i);
			}
		}
		return ret;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值