7

始める前に言っておきますが、これは宿題ではなく、単純で古くて楽しいものです。

今、私はこの質問1/x + 1/y = 1/nに答えることができるアルゴリズムを考え出そうとしています! .

上記のリンクからわかるように、著者は実際の答えではなくヒントだけを求めているので、私も同じことをお願いしたいと思います.

答えの1つが示唆するように (x - n!)(y - n!) = (n!)^2 まで式を単純化し、その時までに (x,y) ペアの組み合わせの数を理解しましたn!^2 の約数と同じです (ここで間違っていたら訂正してください)。

したがって、受け入れられた回答で示唆されているように、N!^2 を構成する各素数のすべての要素の乗算を取得しようとしています。

試行除算を使用して N!^2 を因数分解し、エラトステネスの篩を使用して sqrt(N!^2) までのすべての素数を取得するC のコードを考え出しました。

問題はメモリです。N = 15 で試してみましたが、私の Mac (Quad Core 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 の可能な正の整数解があります。負の整数を数える場合は 2 倍になります。確かに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]

ありがとう

4

3 に答える 3

11

ここでの秘訣は、階乗とは何かを正確に認識することN!です。1からまでのすべての数の積ですN。これはすでに大きな前進です。

したがって、あなたがする必要があるのは、 から までの各数値を素因数分解することだけ1ですN

この意味で、ふるいにかける必要はありませんN!。代わりに、ふるいにかけてsqrt(N)ください。残りはすべての素因数をマージするだけです。

于 2012-03-01T20:14:25.660 に答える
7

さらに簡単なことに、N まで因数分解する必要はありません。素因数を数えるだけです。そして、どの数値が因子であるかを気にせずに行うことができます。

手で15回させてください。

2 の倍数は 15 まで 7 つ、4 の倍数は 3 つ、8 の倍数は 1 つ、合計 11 の 2 の倍数があります。

15 までは 3 の倍数が 5 つ、9 の倍数が 1 つ、合計 3 の倍数が 6 つあります。

15 までは 5 の倍数が 3 つあり、合計で 3 つの 5 の因数があります。

15 までは 7 の倍数が 2 つあり、合計で 2 つの 7 の因数があります。

11 と 13 の倍数はそれぞれ 1 つあります。

だから15!= 2 11 * 3 6 * 5 3 * 7 2 * 11 * 13。

于 2012-03-01T21:32:15.240 に答える
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! の因数分解を数えます。結果のすべての素数のべき乗を 2 倍にします。
于 2012-03-01T23:09:28.043 に答える