给定自然数A,我想找到所有自然数对(B,C),以便B * C *(C + 1)= A

时间:2013-08-17 06:51:39

标签: algorithm math

最快的方法是什么?

我的简单方法:

for (C = 1;C<sqrt(A);C++) {
 B=A/(C*(C+1));
 if B is natural then add B,C to the list of possible pairs. 
}

可以在低于O(sqrt(A))的情况下完成吗?

解决方案

正如Egor Skriptunoff所说,可以在O(cube_root(A))中轻松完成。

这是一个简单的javascript实现。

function findBCs(A) {
    if (A / 2 != Math.floor(A / 2)) return [];
    var solution = [];
    var i;
    var SR3 = Math.pow(A, 1 / 3);
    for (i = 1; i <= SR3; i++) {
        var B, C;
        C = i;
        B = A / (C * (C + 1));
        if (B == Math.floor(B)) {
            solution.push([B, C]);
        }

        B = i;
        C = (-1 + Math.sqrt(1 + 4 * A / B)) / 2;
        if (C == Math.floor(C)) {
            solution.push([B, C]);
        }
    }

    return solution;
}

我接受Meh的答案,因为它应该更好(除了它的实现有点复杂,我还没有测试过。)

3 个答案:

答案 0 :(得分:4)

可以在O(cube_root(A))中完成 实际上,您的某个号码BC必须小于cube_root(A)

答案 1 :(得分:4)

第1步:因素A

步骤2:从A的素数因子中找出所有除数的集合S.

步骤3:对于S中的每个除数c,检查c + 1是否也将A除。如果确实那么b = A /(c *(c + 1))是一个解决方案。 (这使用c和c + 1是互质的。因此,如果c和c + 1除以A,那么c *(c + 1)也是如此。

这种复杂性取决于用于因子AEg的方法,如果你实现例如Pollard-rho(相对简单)那么在最坏的情况下,实现的复杂性大约为O(A ^ 0.25) 。这仍然不是最好的答案。当然有更好的分解算法。此外,如果您的输入是一个具有大量除数的特殊情况,那么因子分解可能很容易,除数的数量也是限制问题。

这种方法的优势当然是你会花时间在一个通常有用的功能(即分解)上,这将简化解决其他类似问题。我自己在Python中实现的Pollard-rho需要总共0.03秒来处理20个示例,其中15个数字由6502发布,这已经至少是1000倍的加速。更复杂的实现应该会带来更大的改进。

为了进行比较,Egor Skriptunoff提出的O(A ^(1/3))方法的快速而肮脏的Python实现需要相同列表的0.7s。对于易于实现的方法,这当然是一个很好的结果。

答案 2 :(得分:-1)

这个python似乎有效:

from __future__ import division
from math import sqrt

def bcc1(a):
    ans = []
    if a % 2: return ans   # for odd a
    for b in range(1, a // 2 + 1):
        c = max(1, int(sqrt(a / b)))
        if b*c*(c+1) == a: 
            ans.append((b,c))
    return ans

for a in range(2, 51, 2):
    print('a: %2i -> (b, c): %r' % (a, bcc1(a)))

产生的输出是:

a:  2 -> (b, c): [(1, 1)]
a:  4 -> (b, c): [(2, 1)]
a:  6 -> (b, c): [(1, 2), (3, 1)]
a:  8 -> (b, c): [(4, 1)]
a: 10 -> (b, c): [(5, 1)]
a: 12 -> (b, c): [(1, 3), (2, 2), (6, 1)]
a: 14 -> (b, c): [(7, 1)]
a: 16 -> (b, c): [(8, 1)]
a: 18 -> (b, c): [(3, 2), (9, 1)]
a: 20 -> (b, c): [(1, 4), (10, 1)]
a: 22 -> (b, c): [(11, 1)]
a: 24 -> (b, c): [(2, 3), (4, 2), (12, 1)]
a: 26 -> (b, c): [(13, 1)]
a: 28 -> (b, c): [(14, 1)]
a: 30 -> (b, c): [(1, 5), (5, 2), (15, 1)]
a: 32 -> (b, c): [(16, 1)]
a: 34 -> (b, c): [(17, 1)]
a: 36 -> (b, c): [(3, 3), (6, 2), (18, 1)]
a: 38 -> (b, c): [(19, 1)]
a: 40 -> (b, c): [(2, 4), (20, 1)]
a: 42 -> (b, c): [(1, 6), (7, 2), (21, 1)]
a: 44 -> (b, c): [(22, 1)]
a: 46 -> (b, c): [(23, 1)]
a: 48 -> (b, c): [(4, 3), (8, 2), (24, 1)]
a: 50 -> (b, c): [(25, 1)]