算法优化(素数因子分解)

时间:2012-03-01 20:11:12

标签: c algorithm math prime-factoring number-theory

在开始之前,让我说:这不是功课,只是简单,陈旧,有趣。

现在,我正在努力想出一个可以回答这个问题的算法1/x + 1/y = 1/n!

正如您可以通过上面的链接看到的,作者只询问提示而不是实际答案,所以我会请求同样的。

我按照one of the answers的建议将表达式简化为(x - n!)(y - n!)=(n!)^ 2,并且到那时我理解了(x的组合数) ,y)对与n!^ 2的除数相同(如果我在这里错了,请纠正我)。

所以,正如accepted answer所建议的那样,我试图得到每个素数组成N的所有因子的乘法!^ 2。

我在C中使用trial division计算了一些代码来分解N!^ 2和Sieve of Eratosthenes以获得所有素数达到sqrt(N!^ 2)。

问题现在是记忆,我试过N = 15而我的Mac(四核6GB内存)几乎死在我身上。问题是记忆力。所以我添加了一些printf并尝试使用N = 11:

Sieve of Eratosthenes took 13339.910000 ms and used 152 mb of memory
n= 11; n!^2 = 1593350922240000; d = 6885
[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,5,5,5,5,7,7,11,11]

列表是N!^ 2的所有主要因素(当然除了1和N!^ 2)。

我想提供一些关于如何最小化内存消耗和可能的优化的提示。

代码如下,这只是一个快速实验,所以我确信它可以进行优化。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <strings.h>
#include <sys/time.h>
#include <assert.h>

//Linked List
struct node {
    struct node * next;
    long val;
};

void addValue(struct node *list, long val) {
    struct node *n = list;

    if (n->val == -1) {
        n->val = val;
        return;
    }

    while (n->next) {
        n = n->next;
    }

    struct node *newNode = malloc(sizeof(struct node));
    newNode->val = val;
    newNode->next = NULL;
    n->next = newNode;
}

void freeLinkedList(struct node *list) {
    struct node *c = list;
    if (!c) return;
    struct node *n = c->next;
    free(c);
    freeLinkedList(n);
}

void printList(struct node *list) {
    struct node *n = list;
    printf("[");
    while (n) {
        printf("%ld", n->val);
        n = n->next;
        if (n) {
            printf(",");
        }
    }
    printf("]\n");
}
//-----------


int fac(int n) {
    if (n == 1) return 1;
    return fac(n-1)*n;
}

//Sieve of Eratosthenes
int sieve_primes(long limit, long **list) {
    struct timeval t1;
    struct timeval t2;
    double elapsedTime = 0;
    gettimeofday(&t1, NULL);

    assert(limit > 0);

    //Create a list of consecutive integers from 2 to n: (2, 3, 4, ..., n).
    long arrSize = limit-1;
    long *arr = malloc(sizeof(long)*arrSize);

    long c = 2;
    for (long i = 0; i < arrSize; i++) {
        arr[i] = c++;
    }   
    assert(arr[arrSize-1] == limit);


    for (long i = 0; i < arrSize; i++) {
        //Let p be equal to the first number not crossed
        long p = arr[i];    
        if (p == 0) continue;

        //Starting from p, count up in increments of p and mark each of these numbers greater than p itself in the list. 
        for (long f = p+p; f < arrSize; f+=p) {
            arr[f] = 0;
        }       
    }

    *list = arr;


    gettimeofday(&t2, NULL);

    elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;      // sec to ms
    elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0;   // us to ms
    printf("Sieve of Eratosthenes took %f ms and used %lu mb of memory\n",elapsedTime, (arrSize * sizeof(int))/1024/1024);
    return arrSize;
}

void trial_division(struct node* list, long n) {    if (n == 1) {
        addValue(list, 1);
        return;
    }
    long *primes;
    long primesSize = sieve_primes(sqrt(n), &primes);   

    struct timeval t1;  
    struct timeval t2;
    double elapsedTime = 0;
    gettimeofday(&t1, NULL);
    for (long i = 0; i < primesSize; i++) {
        long p = primes[i];
        if (p == 0) continue;
        if (p*p > n) break;
        while (n % p == 0) {
            addValue(list, p);
            n/=p;
        }       
    }
    if (n > 1) {
        addValue(list, n);
    }
    free(primes);
}

int main(int argc, char *argv[]) {
    struct node *linkedList = malloc(sizeof(struct node));
    linkedList->val = -1;
    linkedList->next = NULL;


    long n = 11;
    long nF = fac(n);
    long nF2 = nF*nF;
    trial_division(linkedList, nF2);            

    long multOfAllPrimeFactors = 1;
    struct node *c = linkedList;
    while (c) {
        long sumOfVal = 2;
        long val = c->val;              
        c = c->next;
        while(c) {
            long val2 = c->val;
            if (val == val2) {
                sumOfVal++;
                c = c->next;
            } else break;           
        }
        multOfAllPrimeFactors*=sumOfVal;
    }       

    printf("n= %ld; n!^2 = %ld; d = %ld\n", n,nF2, multOfAllPrimeFactors);
    printList(linkedList);  

    freeLinkedList(linkedList);

}

修改

作为一个例子,我将向您展示计算所有可能的正整数解决方案:

  

3!^ 2 = 36 =(3 ^ 2 * 2 ^ 2 * 1 ^ 0)

因此,对于不定方程,存在(1 + 2)(1 + 2)(1 + 0)= 9个可能的正整数解。如果计算负整数,则加倍。我正在使用WolframAlpha来确定。

编辑2:

我想我刚刚发现“这是一个什么因素”,我得到了这个非常有趣的输出:

3! = [2,3]
3!^2 = [2,2,3,3]
3!^3 = [2,2,2,3,3,3]
3!^4 = [2,2,2,2,3,3,3,3]

谢谢:D

3 个答案:

答案 0 :(得分:11)

这里的诀窍是确切地认识到因子N!是什么。它是1N的所有数字的乘积。这已经向前迈出了一大步。

所以你需要做的只是将1N中的每个数字进行素数分析。

从这个意义上讲,您不需要筛选N!。相反,只需筛选sqrt(N)即可。其余的只是合并你所有的主要因素。

答案 1 :(得分:7)

更简单的是,您不需要将数字计算到N.您只需计算素因子。你可以不用担心哪些数字是因素。

让我手工做15。

最多15个有3个倍数的2倍,3倍数4和1个倍数8,总共11个因子为2。

最多15个有3个倍数,3个倍数,总共6个因子3倍。

最多15个有3个倍数的5,总共3个因子为5。

最多15个,有2个倍数为7,总共2个因子为7。

11和13各有1个。

15岁! = 2 11 * 3 6 * 5 3 * 7 2 * 11 * 13.

答案 2 :(得分:5)

找到N的素数因子分解!你必须:

  1. 对于N下的每个素数p:找到S = [N / p] + [N / p 2 ] + [N / p 3 ] + [N / p 4 ] ....([] - 是论证的一部分)。因此,如果我们将除法定义为整体,则公式为:S = N / p + N / p 2 + N / p 3 + N / p 4 ....
  2. 这个S是N中的p的数量!素因素化
  3. 是的,如果你需要分解N!^ 2,只需计算N的分解!并且结果中所有素数的幂都加倍。