2010-10-17 20 views
42

¿Qué es un ejemplo (en código) de una función O (n!)? Debe ejecutar el número apropiado de operaciones en referencia a n; es decir, estoy preguntando sobre la complejidad del tiempo.Ejemplo de O (n!)?

+0

http://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/ –

+4

Para ser pedante, que quiere decir Ω (n!) [Límite inferior sobre crecimiento asintótico] o "tiempo proporcional a n!" [superior e inferior], no O (n!) [límite superior en crecimiento asintótico]. Como O (n!) Es solo el límite superior, muchos algoritmos son O (n!) De forma poco interesante, porque son O (n) u O (n log n) u O (1) o algo así. – jacobm

Respuesta

55

Ahí lo tiene. Este es probablemente el ejemplo más trivial de una función que se ejecuta en el tiempo O(n!) (donde n es el argumento de la función):

void nFacRuntimeFunc(int n) { 
    for(int i=0; i<n; i++) { 
    nFacRuntimeFunc(n-1); 
    } 
} 
+25

Dado que este es un cálculo uno a uno de n !, esta es * la misma definición * de O (n!) Orden de crecimiento. –

+1

¿no es esta O (N)? –

+0

Pensándolo bien, ¿afectará el método recursivo nFac a la complejidad temporal de este algoritmo? –

33

Un ejemplo clásico es el traveling salesman problem a través de la búsqueda de fuerza bruta.

Si hay N ciudades, el método de fuerza bruta probará todas y cada una de las permutación de estas ciudades N para encontrar cuál es la más barata. Ahora el número de permutaciones con N ciudades es N! haciendo su complejidad factorial (O(N!)).

+0

No vi DV, pero tal vez es porque no tiene código de muestra, y la notación de big-o no se proporciona ... – aioobe

+5

@aioobe: ya que la pregunta es "¿Qué es un problema de O (n!)" Y la respuesta es "aquí hay uno", no creo que tengas que decir O (n!) explícitamente ... – Claudiu

+2

Imagina 3 ciudades. Para verificar cualquier ruta potencial, debe verificar la distancia entre dos ciudades dos veces. A-> B y B-> C. Tienes que comenzar desde las 3 esquinas. Sume la distancia en la primera ciudad, por lo que en total son 3 cheques, luego sume la distancia de la 2da ciudad a la 3ra para un total de 6 cheques. ¡eso es 3! = 6. Haga esto para 4 ciudades y los cheques pasen a 24. –

3

el ejemplo más simple :)

pseudocódigo:

input N 
calculate N! and store the value in a vaiable NFac - this operation is o(N) 
loop from 1 to NFac and output the letter 'z' - this is O(N!) 

ahí va :)

Como un ejemplo real: ¿qué hay de generar todas las permutaciones de un conjunto de elementos?

5

Encontrar el determinante con expansión por menores.

Muy buena explicación here.

# include <cppad/cppad.hpp> 
# include <cppad/speed/det_by_minor.hpp> 

bool det_by_minor() 
{ bool ok = true; 

    // dimension of the matrix 
    size_t n = 3; 

    // construct the determinat object 
    CppAD::det_by_minor<double> Det(n); 

    double a[] = { 
     1., 2., 3., // a[0] a[1] a[2] 
     3., 2., 1., // a[3] a[4] a[5] 
     2., 1., 2. // a[6] a[7] a[8] 
    }; 
    CPPAD_TEST_VECTOR<double> A(9); 
    size_t i; 
    for(i = 0; i < 9; i++) 
     A[i] = a[i]; 


    // evaluate the determinant 
    double det = Det(A); 

    double check; 
    check = a[0]*(a[4]*a[8] - a[5]*a[7]) 
      - a[1]*(a[3]*a[8] - a[5]*a[6]) 
      + a[2]*(a[3]*a[7] - a[4]*a[6]); 

    ok = det == check; 

    return ok; 
} 

Código de here. También encontrará los archivos .hpp necesarios there.

5

Hay problemas, que son NP-complete (verificables en tiempo polinominal no determinista). Es decir, si las escalas de entrada, su cálculo necesario para resolver el problema aumenta más que un montón.

Algunos NP-hard problemas son: Hamiltonian path problem ( open img), Travelling salesman problem ( open img)
Algunos NP-complete problemas son: Boolean satisfiability problem (Sat.) ( open img), N-puzzle ( open img), Knapsack problem ( open img), Subgraph isomorphism problem ( open img), Subset sum problem ( open img), Clique problem ( open img), Vertex cover problem ( open img), Independent set problem ( open img), Dominating set problem ( open img), Graph coloring problem ( open img),

Fuente: link 1, link 2

alt text
Fuente: link

+4

NP significa Nondeterministic ** Polynomial **, que significa más rápido que el tiempo exponencial (pero solo en teoría). Factorial es más lento que exponencial, en teoría y en práctica. Entonces, esto es totalmente irrelevante. – Potatoswatter

0

Bogosort es el único "oficial" que he encontrado que se adentra en el O (n!) Zona. Pero no es un O (n!) Garantizado ya que es de naturaleza aleatoria.

+2

-1. Bogosort no es O (n!) Pero incluso más lento. – progo

5

Creo que estoy un poco tarde, pero creo que snailsort es el mejor ejemplo del algoritmo determinista O (n!). Básicamente encuentra la siguiente permutación de una matriz hasta que la ordena.

Parece que este:

template <class Iter> 
void snail_sort(Iter first, Iter last) 
{ 
    while (next_permutation(first, last)) {} 
} 
+0

¡Desde n! se puede definir como la cantidad de formas de permutar una lista de n objetos, este es mi ejemplo favorito, aunque el pseudocódigo sería mejor que C++. ;) – clocksmith

+0

No es del todo obvio que esto tome O (n!) Tiempo. 'next_permutation' toma tiempo lineal, por lo que un cálculo ingenuo da O (n * n!) tiempo (que es estrictamente mayor que O (n!)). Debes argumentar que 'next_permutation' toma O (1) tiempo en promedio para que esto funcione. –

+0

Vale la pena señalar que esto funciona porque 'next_permutation' devuelve la próxima permutación lexicográfica y devuelve verdadero, o devuelve el más pequeño (que es la permutación clasificada) y devuelve falso si no existe una próxima permutación. – Dukeling

0

El método recursivo que probablemente aprendió por tomarse el determinante de una matriz (si se toma el álgebra lineal) toma tiempo O (n!). Aunque particularmente no tengo ganas de codificar todo eso.

3

Cualquier algoritmo que calcule toda la permutación de una matriz dada es O (N!).

1

En C#

¿No sería esto O (N!) En la complejidad del espacio? porque, la cadena en C# es inmutable.

string reverseString(string orgString) { 
    string reversedString = String.Empty; 

    for (int i = 0; i < orgString.Length; i++) { 
     reversedString += orgString[i]; 
    } 

    return reversedString; 
} 
3

printf("Hello World");

Sí, esto es O (n!). Si crees que no es así, te sugiero que leas la definición de BigOh.

Solo agregué esta respuesta debido al hábito molesto que las personas tienen que usar siempre BigOh independientemente de lo que realmente signifiquen.

Por ejemplo, estoy bastante seguro de que la pregunta tenía como objetivo preguntar a Theta (n!), Al menos cn! pasos y no más que Cn! pasos para algunas constantes c, C> 0, pero eligió usar O (n!) en su lugar.

Otra instancia: Quicksort is O(n^2) in the worst case, aunque técnicamente correcta (¡Even heapsort es O (n^2) en el peor de los casos!), Lo que en realidad quieren decir es Quicksort is Omega(n^2) in the worst case.

+1

Aunque es matemáticamente verdadero, la notación O (n) se usa de manera general casi todo el tiempo, incluso para aquellos que * saben * mejor.En particular, se considera engañoso utilizar una clase O superior a la estrictamente necesaria; entonces ningún practicante se referirá a un algoritmo O (n) como O (n²), aunque cualquier algoritmo que esté en O (n) también (por definición) en O (n²) – tucuxi

+0

Esto parece más apropiado como comentario que una respuesta, ya que se limita a señalar un tecnicismo en la pregunta y claramente pasa por alto lo que se preguntó. – Dukeling

0

@clocksmith Tienes toda la razón. Esto no está calculando n !. Tampoco es de O (n!). Lo ejecuté recolectó los datos en la tabla a continuación. Por favor compare la columna 2 y tres. (#nF es la cantidad de llamadas a nFacRuntimeFunc)

n #nF n!

0 0  1 
1 1  1 
2 4  2 
3 15  6 
4 65  24 
5 325 120 
6 1956 720 
7 13699 5040 

Así que claramente si funciona mucho peor que O (n!). A continuación se muestra un código de muestra para calcular n! recursivamente. notarás que es de orden O (n).

int Factorial(int n) 
{ 
    if (n == 1) 
     return 1; 
    else 
     return n * Factorial(n-1); 
} 
0

Tiene razón, las llamadas recursivas deberían tomar exactamente n! hora. aquí hay un código como para probar el tiempo factorial para n valores diferentes. ¡El lazo interno corre para n!tiempo para diferentes valores de j, por lo que la complejidad de bucle interior es Big O (n!)

public static void NFactorialRuntime(int n) 
    { 
     Console.WriteLine(" N Fn N!"); 
     for (int i = 1; i <= n; i++) // This loop is just to test n different values 
     { 
      int f = Fact(i); 
      for (int j = 1; j <= f; j++) // This is Factorial times 
      { ++x; } 
      Console.WriteLine(" {0} {1} {2}", i, x, f); 
      x = 0; 
     } 
    } 

Éstos son el resultado de la prueba para n = 5, es iterar tiempo exactamente factorial.

N Fn N! 
    1 1 1 
    2 2 2 
    3 6 6 
    4 24 24 
    5 120 120 

Función exacta con la complejidad del tiempo n!

// Big O(n!) 
public static void NFactorialRuntime(int n) 
    { 
     for (int j = 1; j <= Fact(i); j++) { ++x; } 
     Console.WriteLine(" {0} {1} {2}", i, x, f); 
    } 
Cuestiones relacionadas