Esto se puede convertir fácilmente a otro tipo de problema, que puede ser resuelto de manera más eficiente. Todo lo que se necesita es convertir las matrices en permutaciones, es decir, cambiar los valores a sus ID. Por lo que sus matrices:
L1 = [2,3,4,5]
L2 = [2,5,4,3]
se convertirían en
P1 = [0,1,2,3]
P2 = [0,3,2,1]
con la asignación 2->0, 3->1, 4->2, 5->3
. Esto solo se puede hacer si no hay elementos repetidos. Si hay, entonces esto se vuelve más difícil de resolver.
Convirtiendo la permutación de uno a otro se puede convertir a un problema similar (Number of swaps in a permutation) invirtiendo la permutación objetivo en O (n), componiendo las permutaciones en O (n) y luego encontrando el número de permutas desde allí a un permutación de identidad en O (m). Dado:
int P1[] = {0, 1, 2, 3}; // 2345
int P2[] = {0, 3, 2, 1}; // 2543
// we can follow a simple algebraic modification
// (see http://en.wikipedia.org/wiki/Permutation#Product_and_inverse):
// P1 * P = P2 | premultiply P1^-1 *
// P1^-1 * P1 * P = P1^-1 * P2
// I * P = P1^-1 * P2
// P = P1^-1 * P2
// where P is a permutation that makes P1 into P2.
// also, the number of steps from P to identity equals
// the number of steps from P1 to P2.
int P1_inv[4];
for(int i = 0; i < 4; ++ i)
P1_inv[P1[i]] = i;
// invert the first permutation in O(n)
int P[4];
for(int i = 0; i < 4; ++ i)
P[i] = P2[P1_inv[i]];
// chain the permutations in O(n)
int num_steps = NumSteps(P, 4); // will return 2
// now we just need to count the steps in O(num_steps)
para contar los pasos, un algoritmo simple se puede diseñar, tales como:
int NumSteps(int *P, int n)
{
int count = 0;
for(int i = 0; i < n; ++ i) {
for(; P[i] != i; ++ count) // could be permuted multiple times
swap(P[P[i]], P[i]); // look where the number at hand should be
}
// count number of permutations
return count;
}
Esto siempre intercambia un artículo para un lugar en el que debería estar en la permutación de identidad, por lo tanto, en cada paso deshace y cuenta un intercambio. Ahora, siempre que el número de intercambios que devuelve sea realmente mínimo, el tiempo de ejecución del algoritmo está limitado por él y se garantiza que finalizará (en lugar de quedar atrapado en un ciclo infinito). Se ejecutará en O(m)
swaps o O(m + n)
iteraciones de bucle donde m
es el número de swaps (el count
devuelto) y n
es el número de elementos en la secuencia (4
). Tenga en cuenta que m < n
siempre es cierto. Por lo tanto, esto debería ser superior a las soluciones O(n log n)
, ya que el límite superior es O(n - 1)
de swaps o O(n + n - 1)
de iteraciones de bucle aquí, que es prácticamente O(n)
(se omite el factor constante de 2 en este último caso).
El algoritmo solo funcionará para permutaciones válidas, se repetirá infinitamente para secuencias con valores duplicados y realizará acceso de matriz fuera de límites (y bloqueo) para secuencias con valores que no sean [0, n)
. Se puede encontrar un caso de prueba completo here (compilaciones con Visual Studio 2008, el algoritmo en sí mismo debería ser bastante portátil). Genera todas las permutaciones posibles de longitudes 1 a 32 y las comprobaciones frente a soluciones, generadas con la primera búsqueda de ancho (BFS), parece funcionar para todas las permutaciones de longitudes 1 a 12, luego se vuelve bastante lento, pero supongo que continuará funcionando .
Estoy probando https://www.spoj.pl/problems/YODANESS/ – Dogbert
me parece igual que ese problema le pide que cuente inversiones, no lo que estás preguntando aquí. – IVlad
¿Está pidiendo soluciones a los problemas SPOJ el camino a seguir? ¿No deberías intentar resolverlo tú mismo? ¿Por qué no pides consejos en lugar de la respuesta? – MAK