Enumere los números naturales factorizados primos hasta N en orden ascendente

8

Para una nlista dada, la factorización prima de todos los números naturales entre 1y nen orden ascendente. Por ejemplo, para n= 10 la salida sería:

1:
2: 2^1
3: 3^1
4: 2^2
5: 5^1
6: 2^1 3^1
7: 7^1
8: 2^3
9: 3^2
10: 2^1 5^1

Requisitos:

  • No puede simplemente iterar sobre los números y factorizar cada uno de ellos. (A menos que sepa cómo factorizar un número en el tiempo logarítmico, y luego dudo que esté perdiendo el tiempo resolviendo acertijos). Esto es demasiado ineficiente.
  • El resultado debe ser como en el ejemplo anterior: en cada línea, el número y la lista de sus factores primos.
  • Tenga en cuenta que npuede ser muy grande, por lo que podría no ser factible generar todas las factorizaciones en la memoria y luego ordenarlas al final. (Pero si tiene una solución inteligente que viola esto, publíquela también).
Petr Pudlák
fuente

Respuestas:

4

C ++

Implementa un tamiz usando primos hasta sqrt(n). Mantiene una lista de listas vinculadas para realizar un seguimiento de qué números primos dividen qué números próximos. Cada vez que pse usa un primo , su Factorestructura se mueve pranuras hacia abajo en la lista.

La mayor parte del tiempo se dedica solo printfa responder.

#include <stdio.h>
#include <stdlib.h>

// lists of Factors represent known prime factors of a number                                                                                              
struct Factor {
  Factor(int p) : prime(p), next(NULL) { }
  int prime;
  Factor *next;
};

int main(int argc, char *argv[]) {
  long long n = atoll(argv[1]);

  // figure out the maximum prime we need to sieve with                                                                                                    
  int maxp = 1;
  while ((long long)maxp * maxp < n) maxp++;
  maxp--;

  // find next power of two up from that for our circular buffer size                                                                                      
  int size = 1;
  while (size < maxp) size *= 2;
  int mask = size - 1;

  // allocate circular buffer of lists of sieving prime factors for upcoming numbers                                                                       
  Factor **factors = new Factor*[size]();

  printf("1:\n");

  for (long long x = 2; x < n; x++) {
    Factor *list = factors[x & mask];
    factors[x & mask] = NULL; // reset so it can hold the list for x + size                                                                                

    if (!list && x <= maxp) { // x is a prime we need to sieve with - make new list with just itself                                                       
      list = new Factor(x);
    }

    // print factor list, push each Factor along to the next list.                                                                                         
    printf("%lld:", x);
    long long y = x;
    while (list) {
      Factor *f = list;
      list = f->next;
      int p = f->prime;

      // count how many factors of p are in x                                                                                                              
      int k = 1;
      y /= p;
      while (y % p == 0) {
        k++;
        y /= p;
      }
      printf(" %d^%d", p, k);

      // splice f into the list for the next number it divides                                                                                             
      long long z = x + f->prime;
      f->next = factors[z & mask];
      factors[z & mask] = f;
    }
    // remaining part of x must be prime                                                                                                                   
    if (y != 1) printf(" %lld^1", y);
    printf("\n");
  }
}
Keith Randall
fuente
4

A continuación se muestra mi intento, en el esquema R5RS (descargo de responsabilidad: en realidad no soy un Schemer (¡todavía!), Así que perdón por el (probablemente) terrible código).

(define count 10)

; `factors` is our vector of linked-lists of factors.  We're adding to these
; as we go on.
(define factors (make-vector count 'not-found))
(vector-set! factors 0 '())

; `primes-so-far` contains all the prime numbers we've discovered thus far.
; We use this list to speed up the dividing of numbers.
;   `primes-so-far-last` is a ref to the last entry in the `primes-so-far`
; list, for O(1) appending to the list.
(define primes-so-far '(dummy))
(define primes-so-far-last primes-so-far)

;; Helpers
(define (factor-ref n)
  (vector-ref factors (- n 1)))

(define (factor-cached? n)
  (not (eq? (vector-ref factors (- n 1)) 'not-found)))

(define (factor-put n factor)
  (let* ((rest        (/ n factor))
         (factor-cell (cons factor (factor-ref rest))))
    (vector-set! factors (- n 1) factor-cell)
    factor-cell))

(define (prime-append n)
  (let ((new-prime-cell (cons n '())))
    (set-cdr! primes-so-far-last new-prime-cell)
    (set!     primes-so-far-last new-prime-cell)
    new-prime-cell))

;; The factor procedure (assumes that `[1..n-1]` have already been factorized).
(define (factor n)
  (define (divides? m n)
    (= (modulo n m) 0))

  ; n       the number to factor.
  ; primes  the list of primes to try to divide with.
  (define (iter n primes)
    (cond ((factor-cached? n)
           (factor-ref n))

          ((null? primes)
           ; no primes left to divide with; n is prime.
           (prime-append n)
           (factor-put n n)) ; the only prime factor in a prime is itself

          ((divides? (car primes) n)
           (factor-put n (car primes))
           (factor-ref n))

          (else
           (iter n (cdr primes)))))

  (iter n (cdr primes-so-far)))

(define (print-loop i)
  (if (<= i count)
      (begin
        (display i)
        (display ": ")
        (display (factor i))
        (newline)
        (print-loop (+ i 1)))))

(print-loop 1)

Imprime como:

1: ()
2: (2)
3: (3)
4: (2 2)
5: (5)
6: (2 3)
7: (7)
8: (2 2 2)
9: (3 3)
10: (2 5)

(No exactamente como en la descripción de la tarea, pero todo lo que tendría que hacer para obtener esa salida es doblar la lista y fusionar las repeticiones del mismo número, durante la parte de salida del código. La representación / algoritmo interno aún sería lo mismo.)

La idea es almacenar en caché los valores calculados anteriormente, pero hacer uso del hecho de que los factores de nes el primer factor primo de ny los factores primos de (n / primer factor). Pero esto último ya se conoce, por lo que simplemente reutilizamos la lista de factores ya existente para ese número menor. Por lo tanto, para cada número en el [1..n]que no es primo, se almacena una sola celda de contras.

Para cada número, se crea y almacena una sola celda de contras. Por lo tanto, este enfoque debe ejecutarse con O(n)el uso del almacenamiento. No tengo idea de si es posible expresar perfectamente la complejidad del tiempo.

Luciérnaga
fuente
0

C (gcc)

#include <stdio.h>
#include <stdlib.h>

#define true 1
#define false 0

int square(int a){
	return a * a;
}

void prime_factors(int n){
	// this is an array of n elements, which will contain all found primes.
	// curprime stores the index of the last found prime, which saves us searching for where to insert the next one and things.
	int* primes = calloc(sizeof(int), n);
	int curprime = 0;

	printf("1:\n"); // Micro optimization, and rids me of the messing around that is 1.
	for(int i=2; i<=n; i++){
		// Print the current i.
		printf("%i: ",i);

		// Define val, which we'll slowly make smaller and smaller. Mwahaha.
		int val = i;
		int isprime = true;	// This will be set to false if it's divisible by any primes, which of course, means it's also not a prime.

		// Loop through primes, this loop stops if we've reached either more than sqrt(count) primes, or val is equal to zero (as such, it's fully prime factorized).
		for(int*prime_pointer = primes; val && square((int)(prime_pointer-primes)) < curprime; prime_pointer++){
			int prime = *prime_pointer;
			// if the current val is divisible by the current prime.
			while(val%prime == 0){
				isprime = false; 	// We know that this number isn't prime.
				val = val / prime;	// Divide val by it.
				printf("%i ",prime);// And write this prime.
			}
		}
		if(isprime){	// If this number is a prime.
			printf("%i ",i);	// Append it to its own list.
			primes[curprime++] = i;	// And append this new prime to our list of primes.
		}
		printf("\n");	// Terminate the line with a newline. Duh...
	}
}

int main(int argc, char** argv){
	prime_factors(1000);
}

Define la función prime_factorsque toma un número entero ny sale a través de printf en el siguiente formato:

1:
2: 2 
3: 3 
4: 2 2 
5: 5 
6: 2 3 
7: 7 
8: 2 2 2 
9: 3 3 
10: 2 

Esto usa O (n) memoria adicional, y no estoy seguro de la complejidad del tiempo.

Pruébalo en línea!

Un taco
fuente