Combitronics和Prime Factorization:计算(m,n)对的数量,其中GCD(m,n)= x

时间:2014-05-27 16:15:40

标签: java algorithm prime-factoring greatest-common-divisor

  

计算(m,n)的对的数量,其中GCD(m,n)= x,比如x = 1,   1 <= m <= M = 10 ^ 5且1 <= n <= N = 10 ^ 5.

     

M和N将被给予

我知道我们可以使用(Brute Force)2迭代器迭代M和N并检查GCD是否= = 1增加可能的对数。

但是这只适用于较小的数字,而对于较大的数字而言,它需要花费很多时间。像M = 100000和N = 100000

我们可以使用素因子来计算。

注意:我只想要可能的对数而不是对。

1 个答案:

答案 0 :(得分:1)

让我们从您的强力算法开始:

for (n = 1; n <= N; n++) {
    for (m = 1; m <= M; m++) {
        if (gcd(m, n) == x) count++;
    }
}

x大于1时,您可以加快速度,因为如果nm的gdc为x,则这些数字本身必须是x

for (n = x; n <= N; n += x) {
    for (m = x; m <= M; m += x) {
        if (gcd(m, n) == x) count++;
    }
}

在这些循环中,我们可以将所有数字除以x

int NN = N / x;
int MM = M / x;

for (n = 1; n <= NN; n++) {
    for (m = 1; m <= MM; m++) {
        if (gcd(m, n) == 1) count++;
    }
}

检查gdc为1是对互质对的测试。一些研究导致Wikipedia,并产生一个整洁(和奢侈的插图)算法,以生成所有互质对:

#define NN (N / X)
#define MM (M / X)

void spread(int m, int n, int *count)
{
    if (n > NN) return;
    if (m > MM) return;

    if (n != m && m <= NN) (*count)++;
    (*count)++;

    spread(2*m - n, m, count);
    spread(2*m + n, m, count);
    spread(m + 2*n, n, count);
}

int main()
{
    int count = 1;

    spread(2, 1, &count);
    spread(3, 1, &count);

    printf("%d\n", count);

    return 0;
}

计数从1开始,因为对生成器不生成(1,1),这也符合您的标准。如果M大于或等于N,则代码有效。如果没有,交换它们。

这种自下而上的方法比环路快得多,就像Erathostenes的筛子比对一系列数字进行天真的素性检查一样快。

我担心这是C,而不是Java。 count作为指针传递;我猜Java成语可能是一个参考。当然,您也可以从spread返回计数并累积。 (如果NNN等不是全局的,那就太好了,但是我确定你会用Java包装一个漂亮,整洁的类。)

编辑:上面的代码是递归的,需要大量的堆栈空间。如果线性化代码并使用队列,则可以将所需空间从堆栈迁移到堆。代码看起来像这样:

int spread(m, n)
{
    Queue q;
    int count = 1;

    q.push(m, n);

    while (!q.empty()) {
        int m, n;

        q.pull(&m, &n);

        if (n <= NN && m <= MM) {
            if (n != m && m <= NN) count++;
            count++;

            q.push(2*m - n, m);
            q.push(2*m + n, m);
            q.push(m + 2*n, n);
        }
    }

    return count;
}

int main()
{
    Queue q;
    int count = 1;

    count += spread(2, 1);
    count += spread(3, 1);

    printf("%d\n", count);

    return 0;
}

如果MN超过100,000,则需要很长时间才能运行。但是您可以轻松地将其并行化,因为(2,1)和(3,1)情况是独立的。