繁体   English   中英

所有自然数总和N,反转总和为1

[英]All natural numbers which sum up to N and where the inverses sum up to one

我有一个问题要解决。 给出N自然数。 我需要找到一个自然数列表,它总结了给定的数字,同时反转最多为1。

a + b + c + ... = N
1/a + 1/b + 1/c + ... = 1

abc不一定是唯一的。

我在Java中提出了以下代码。 它适用于简单的情况,但对于N > 1000已经非常慢。

如何重写方法,以便即使对数百万人也能快速工作? 也许,我应该放弃递归或用数学技巧切断一些分支,我想念?

SSCEE:

private final static double ONE = 1.00000001;

public List<Integer> search (int number) {
    int bound = (int)Math.sqrt(number) + 1;
    List<Integer> list = new ArrayList<Integer>(bound);

    if (number == 1) {
        list.add(1);
        return list;
    }

    for (int i = 2; i <= bound; i++) {
        list.clear();
        if (simulate(number, i, list, 0.0)) break;
    }

    return list;
}


//TODO: how to reuse already calculated results?
private boolean search (int number, int n, List<Integer> list, double sum) {
    if (sum > ONE) {
        return false;
    }

    //would be larger anyway
    double minSum = sum + 1.0 / number;
    if (minSum > ONE) {
        return false;
    }

    if (n == 1) {
        if (minSum < 0.99999999) {
            return false;
        }

        list.add(number);
        return true;
    }

    boolean success = false;
    for (int i = 2; i < number; i++) {
        if (number - i > 0) {
            double tmpSum = sum + 1.0 / i;
            if (tmpSum > ONE) continue;

            list.add(i);
            success = search(number - i, n - 1, list, tmpSum);
            if (!success) {
                list.remove(list.size() - 1);
            }

            if (success) break;
        }
    }

    return success;
}

由Graham,RL于1963年发表的论文“分区上的一个定理”表明,对于N> 77,存在一种解决方案,其中使用的数字是直接的,并提出了一种算法来找到这样的分解。

算法如下:

  • 如果N小于333,请使用预先计算的表来获取结果。
  • 如果N是奇数,找到分解d1, d2, d3, d4, ..., dk(N-179)/2 ,然后是3, 7, 78, 91, 2*d1, 2*d2, 2*d3, ..., 2*dk是N的分解
  • 如果N是偶数,找到分解d1, d2, d3, d4, ..., dk(N-2)/2 ,然后是2, 2*d1, 2*d2, 2*d3, ..., 2*dk是N的分解

但由于你不关心在分解中有不同的数字,你可以将预计算结果的表的大小减小到60,如果N是奇数,找到分解d1, d2, d3, d4, ..., dk(N-9)/2 ,然后为3, 6, 2*d1, 2*d2, 2*d3, ..., 2*dk为N的分解。

首先,更改第二个条件,以便您不必执行任何浮点算术。 改变(1 / a + 1 / b + 1 / c)= 1到bc + ac + ab = abc。 您可以使用O(k)分割来计算(提示:先计算右侧)。

第二,巩固你的数字。 示例:如果您有a,b,c,a,b作为输入,则合并dupes并将其存储为两个a,两个b和一个c。

第三,有一种基于DP的解决方案可以有效地解决第一个问题。 您还必须存储所有部分答案。 但是,您可以非常有效地存储部分答案。 例如。 存储“x = bc + ac + ab”和“y = abc”作为部分解。 将d添加到混合时,您有xnew = x * d + y和ynew = y * d。

如果您使用这三个指针,您的解决方案可能会更有效。

如果数字不必是整数,则a = b = c = ... = sqrt(N)是一个解。

如果允许负数,则找到ab使得8a+3b+1=N (您可以使用Euclide的算法计算它们)然后您想要的列表是:数字3(3a次),数字2(2b)次)和数字1(1-ab次)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM