2011-12-26 27 views
7

¿Cuál es el mejor algoritmo (más eficiente) para encontrar todas las raíces de poder enteros de un número?Encontrar raíces de poder enteras

Es decir, dado un númeron, quiero encontrarb (base) y e (exponente) de tal manera que

n = b e

Quiero obtener todos los pares de valores posibles de b y e

Sal: nb y e han de ser números enteros positivos .

+0

¿'' e' tiene que ser un número entero? – huitseeker

+0

Lo siento, me olvidé de mencionar que he actualizado la pregunta – Gautam

+1

Todavía estoy buscando algo. estado haciendo eso durante más de 45 minutos – Gautam

Respuesta

4

Creo que el enfoque de fuerza bruta debería funcionar: pruebe todos e s de 2 (1 es una solución trivial) y más, tomando r = n^1/e, double. Si r es menor que 2, deténgase. De lo contrario, calcule ceil(r)^e y floor(r)^e, y compárelos con n (necesita ceil y floor para compensar los errores en las representaciones de coma flotante). Suponiendo que sus enteros encajen en 64 bits, no necesitaría probar más de 64 valores de e.

Aquí se muestra un ejemplo en C++:

#include <iostream> 
#include <string> 
#include <sstream> 
#include <math.h> 
typedef long long i64; 
using namespace std; 
int main(int argc, const char* argv[]) { 
    if (argc == 0) return 0; 
    stringstream ss(argv[1]); 
    i64 n; 
    ss >> n; 
    cout << n << ", " << 1 << endl; 
    for (int e = 2 ; ; e++) { 
     double r = pow(n, 1.0/e); 
     if (r < 1.9) break; 
     i64 c = ceil(r); 
     i64 f = floor(r); 
     i64 p1 = 1, p2 = 1; 
     for (int i = 0 ; i != e ; i++, p1 *= c, p2 *= f); 
     if (p1 == n) { 
      cout << c << ", " << e << endl; 
     } else if (p2 == n) { 
      cout << f << ", " << e << endl; 
     } 
    } 
    return 0; 
} 

Cuando se invoca con 65536, que produce este resultado:

65536, 1 
256, 2 
16, 4 
4, 8 
2, 16 
+0

Parece plausible, ¿Puedes aclarar la solución con algún código? – Gautam

+0

@dasblinkenlight: es la idea correcta para una solución perfecta. Solo tiene que probar 'e' de' 2' a 'log2 (n)' (logaritmo base 2). Lo único es que el código de exponenciación 'for (int i = 0; i! = E; i ++, p1 * = c, p2 * = f);' está lejos de ser óptimo (puede hacer menos de '2 * log2 (e) 'multiplicaciones en lugar de multiplicaciones' e'). Pero el concepto principal es correcto de todos modos. –

+0

@SergeDundich Mantuve el código ingenuo 'power (c, e)' porque 'e' tiene un límite bajo de 64. El algoritmo inteligente de' power (c, e) 'crearía más preguntas (incluso el bucle' for' Tengo allí ahora podría beneficiarse de un comentario, un algoritmo de poder 'log2' sería aún menos obvio) así que guardé el algoritmo trivial. – dasblinkenlight

3

Depende de las dimensiones de la tarea si mi enfoque se ajustará a sus necesidades.

Antes que nada hay una solución obvia: e = 1, ¿no? A partir de ahí si quiere encontrar todas las soluciones: todos los algoritmos que se me ocurren requieren para encontrar algún factor primo de n. Si esto es solo una tarea independiente, no se puede hacer nada mejor que la fuerza bruta en los números primos (si no estoy equivocado). Después de encontrar el primer factor primo p y su exponente correspondiente (es decir, el número más alto k tal que p^k/n) necesita comprobar e solo los divisores de k. Para cada uno de estos exponentes l (de nuevo itera todos los divisores de k) puede usar la búsqueda binaria para ver si la raíz l de n es un número entero (equivalente a encontrar una nueva solución).

+1

"(si no estoy equivocado)" Usted está equivocado. La [factorización de enteros] (http://en.wikipedia.org/wiki/Integer_factorization) tiene algoritmos mucho más rápidos que "fuerza bruta en los números primos". Y _definir todas las raíces de poder entero_ que la pregunta original plantea es un problema mucho más simple (tiempo polinomial). –

+0

Como dirían algunas personas: "Lo único mejor que estar en lo cierto es estar equivocado". Gracias por educarme. PD: Poco tiempo después de haber publicado me di cuenta de que la solución que propongo es algo intermedio y no podía pensar en un ajuste del problema para el cual mi solución sería óptima (probablemente factorizando un gran número del que sabe que hay muy pequeño factor primo?). –

7

En primer lugar encontrar la factorización prima de n: n = p1e1 p2e2 p3e3 ...

luego encontrar el máximo común divisor de ge1, e2, e3, ... Al usar el Euclidean algorithm.

Ahora para cualquier factor de e de g, puede utilizar:

b = p1e1/e p2e2/e p3e3/e ...

Y tiene n = be.

+4

En realidad estaba tratando de implementar un algoritmo de factorización principal y necesitaba resolver este problema. Irónicamente, me estás pidiendo que encuentre los factores principales. – Gautam

+0

gran enfoque! – FUD

+0

@ChingPing: está muy lejos de ser un gran enfoque. ** Encontrar raíces de poder enteras ** es un problema de tiempo polinomial muy simple, mientras que la factorización de enteros es un problema muy complicado, sin algoritmos de tiempo polinomial conocidos. –

2

mezclar los enfoques de interjay y dasblinkenlight. Primero busca todos los factores primos pequeños (si los hay) y sus exponentes en la factorización prima de n. El valor apropiado de 'pequeño' depende de n, por medio de tamaño n, p <= 100 puede ser suficiente, por grann, p <= 10000 o p <= 10^6 puede ser más apropiado. Si encuentra algún pequeño factor primo, sabe que e debe dividir el mayor divisor común de todos los exponentes que encontró. Muy a menudo, ese gcd será 1. De todos modos, el rango de posibles exponentes se reducirá, si n no tiene factores primos pequeños, usted sabe que e <= log(n)/log(small_limit), que es una buena reducción de log(n)/log(2), si ha encontrado un par de pequeños factores, el gcd de sus exponentes es g, y el cofactor restante de n es m, solo necesita verificar los divisores g que no excedan log(m)/log(small_limit).

Cuestiones relacionadas