======= Permutaciones ======= FIXME (¿Agregar definición de permutación? ¿noción intuitiva? ¿función biyectiva de un conjunto en sí mismo? Por ahora queda el link a wikipedia)[[https://es.wikipedia.org/wiki/Permutaci%C3%B3n|Permutación Wikipedia]] Dado un arreglo de $n$ elementos (sus índices se encuentran en $ \left \{0,1, \dots, n-1 \right \}$), se plantea el problema de hallar todas las permutaciones del mismo. Ejemplo, si $n=3$, todas las permutaciones posibles de $\left \{ 0,1,2 \right \}$ son: *1: $(0,1,2)$ *2: $(0,2,1)$ *3: $(1,0,2)$ *4: $(1,2,0)$ *5: $(2,0,1)$ *6: $(2,1,0)$ En general, dado un conjunto de $n$ elementos, tenemos $n!$ permutaciones posibles. Esto se ve claramente si uno piensa en el proceso de construcción de una permutación. El primer elemento puede ser cualquiera de los $n$ posibles, para el segundo hay $n-1$ opciones, pues podrá tener cualquier valor a excepción del valor elegido para el primer elemento, y así sucesivamente. De esta forma se ve que hay $n! = n(n-1)\cdots1$ permutaciones posibles para un arreglo. Además, este proceso constructivo da una forma muy natural de escribir un código que calcule todas las permutaciones de un arreglo. ======= Generar Permutaciones ======= ===== Forma 1 (recursiva) ===== Usaremos ''permutacion'' como un vector donde construiremos todas las permutaciones y ''elegido'' como un arreglo booleano (o idealmente un [[cpp-avanzado:bitset|Bitset]]), que nos dirá en la $i$-ésima posición, si el $i$-ésimo elemento ya fue elegido en el proceso constructivo de la permutación (y es un elemento actual de ''permutacion''). void generarPermutaciones() { if (permutacion.size() == n) { // hacemos lo que queremos con la permutacion armada } else { for(int i = 0; i < n; i++) // iteramos todos los candidatos a agregar en la permutacion { if (!elegido[i]) { elegido[i] = true; // lo marcamos para no elegirlo nuevamente en el proceso permutacion.push_back(i); // lo agregamos a la permutacion generarPermutaciones(); // seguimos el proceso de construccion elegido[i] = false; // lo desmarcamos como elegido permutacion.pop_back(); // lo sacamos de la permutacion actual } } } } ===== Forma 2 (iterativa) ===== Otra forma de generar todas las permutaciones eficientemente es utilizar la función ''next_permutation'' que viene implementada en la librería estándar de C++. Si uno tiene un arreglo de $n$ elementos, y estos elementos pueden compararse con el operador $<$ (es decir está implementado el ''operator <'' para el tipo de los elementos del arreglo en cuestión), entonces al escribir: next_permutation(arreglo.begin(),arreglo.end()); Tendremos como resultado que se modificó ''arreglo'' de manera in-place, a la siguiente permutación lexicográfica (que sea distinta a la original, esto cobra importancia si tenemos elementos repetidos). Por ejemplo: * $(0,1,2,3) \xrightarrow{\texttt{next_permutation}} (0,1,3,2)$ * $(0,3,1,2) \xrightarrow{\texttt{next_permutation}} (0,3,2,1)$ * $(0,2,1,1,3) \xrightarrow{\texttt{next_permutation}} (0,2,1,3,1)$ * $(0,3,2,1,1) \xrightarrow{\texttt{next_permutation}} (1,0,1,2,3)$ De esta forma, si queremos **generar todas** las permutaciones de un arreglo, **debemos comenzar con la permutación lexicográficamente más chica** (por ejemplo, llamando a [[cpp-avanzado:algorithm:sort | sort]] en el arreglo), y luego ejecutar el siguiente código. do { // Hacemos lo que queremos con la permutacion } while (next_permutation(arreglo.begin(),arreglo.end()));