Алгоритм оптимизации (Prime Factorization) - PullRequest
7 голосов
/ 02 марта 2012

Прежде чем начать, позвольте мне сказать: это не домашняя работа, просто старая, забавная.

Теперь я пытаюсь придумать алгоритм, который может ответить на этот вопрос 1 / x +1 / y = 1 / n! .

И, как вы можете видеть по ссылке выше, автор попросил только подсказки, а не фактический ответ, поэтому я бы любезно попросил то же самое.

Я упрощал выражение до (x - n!) (Y - n!) = (N!) ^ 2, как подсказал один из ответов , и к тому времени я понял, чтоколичество комбинаций пар (x, y) совпадает с числом делителей n! ^ 2 (поправьте меня, если я ошибаюсь).

Итак, как подсказывает принятый ответ , я пытаюсь получить умножение всех факторов каждого простого числа, составляющего N! ^ 2.

Я придумал некоторый код на C, используя пробное деление для разложения N! ^ 2 и Сито Эратосфена для получения всех простых чисел вплоть до sqrt (N! ^ 2).

Теперь проблема в памяти, я пыталсяс N = 15, и мой Mac (Quad Core 6 ГБ памяти) почти умер от меня.Проблема была в памяти.Поэтому я добавил несколько 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 ]

11 голосов
/ 02 марта 2012

Хитрость в том, чтобы точно узнать, что такое факториал N!. Это произведение всех чисел от 1 до N. Это уже огромный шаг вперед.

Итак, что вам нужно сделать, это просто разложить каждое из чисел от 1 до N.

В этом смысле вам не нужно просеивать до N!. Вместо этого просто просейте до sqrt(N). А остальное просто объединяет все ваши главные факторы.

7 голосов
/ 02 марта 2012

Еще проще, вам не нужно разлагать числа до N. Вы просто должны посчитать простые факторы. И это можно сделать, не беспокоясь о том, какие цифры являются факторами.

Позвольте мне сделать 15 вручную.

До 15 существует 7 крат, 2, 3, кратных 4, и 1, кратных 8, всего 11 факторов, равных 2.

До 15 есть 5 кратных 3, и одно кратное 9, в общей сложности 6 факторов, равных 3.

До 15 есть 3, умноженные на 5, всего 3 фактора, равных 5.

До 15 есть 2, умноженные на 7, всего 2 фактора, равных 7.

1 кратно 11 и 13.

Итак, 15! = 2 11 * 3 6 * 5 3 * 7 2 * 11 * 13.

5 голосов
/ 02 марта 2012

Чтобы найти простую факторизацию N! Вы должны:

  1. Для каждого простого числа p в N: найдите 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 - это число p в N! первичная факторизация
  3. И да, если вам нужно разложить N! ^ 2, просто посчитайте разложение N! и удвоить силы всех простых чисел в результате.
...