2008-11-19 15 views
7

Tengo una pregunta independiente del idioma sobre un algoritmo.ordenar números por algoritmo de suma

Esto viene de un desafío de programación (probablemente simple) que leí. El problema es que soy demasiado estúpido para descubrirlo, y lo suficientemente curioso como para molestarme.

El objetivo es ordenar una lista de enteros por orden ascendente intercambiando las posiciones de los números en la lista. Cada vez que intercambias dos números, debes sumarlos a un total acumulado. El desafío es producir la lista ordenada con el total de ejecución más pequeño posible. Ejemplos:

3 2 1 - 4 
1 8 9 7 6 - 41 
8 4 5 3 2 7 - 34 

Aunque usted es libre para simplemente dar la respuesta si se quiere, si prefiere ofrecer un "toque" en la dirección correcta (si tal cosa es posible), yo preferiría que .

Respuesta

6

Solo lea los dos primeros párrafos si solo quiere una pista. Hay una solución eficiente para esto (a menos que haya cometido un error, por supuesto). Primero ordena la lista. Ahora podemos escribir la lista original como una lista de productos de ciclos disjuntos.

Por ejemplo 5,3,4,2,1 tiene dos ciclos, (5,1) y (3,4,2). Se puede pensar que el ciclo comienza en 3, 4 en el punto 3, 2 en el punto 4 y 4 en 3. lugar. El objetivo final es 1,2,3,4,5 o (1) (2) (3) (4) (5), cinco ciclos disjuntos.

Si cambiamos dos elementos de diferentes ciclos, digamos 1 y 3, entonces obtenemos: 5,1,4,2,3 y en notación de ciclo (1,5,3,4,2). Los dos ciclos se unen en un ciclo, esto es lo opuesto a lo que queremos hacer.

Si cambiamos dos elementos del mismo ciclo, digamos 3 y 4, obtenemos: 5,4,3,2,1 en notación de ciclo (5,1) (2,4) (3). El ciclo único se divide en dos ciclos más pequeños. Esto nos acerca al objetivo de todos los ciclos de longitud 1. Observe que cualquier cambio de dos elementos en el mismo ciclo divide el ciclo en dos ciclos.

Si podemos descifrar el algoritmo óptimo para cambiar un ciclo, podemos aplicarlo para todos los ciclos y obtener un algoritmo óptimo para todo el género. Un algoritmo es tomar el elemento mínimo en el ciclo y cambiarlo por la posición en la que se encuentra. Entonces, para (3,4,2), cambiaríamos 2 por 4. Esto nos deja con un ciclo de longitud 1 (el elemento simplemente cambió a la posición correcta) y un ciclo de tamaño uno más pequeño que antes. Entonces podemos aplicar la regla nuevamente. Este algoritmo cambia la longitud del ciclo del elemento más pequeño -1 veces y cada otro elemento una vez.

Para transformar un ciclo de longitud n en ciclos de longitud 1 se requieren n - 1 operaciones. Cada elemento debe ser operado al menos una vez (piense en cada elemento a clasificar, debe moverse a su posición correcta). El algoritmo que propuse opera en cada elemento una vez, lo que todos los algoritmos deben hacer, luego cada otra operación se realizó en el elemento mínimo. Ningún algoritmo puede hacerlo mejor.

Este algoritmo toma O (n log n) para ordenar luego O (n) para mezclar ciclos. La resolución de un ciclo toma O (duración del ciclo), la longitud total de todos los ciclos es n, por lo que el costo de las operaciones del ciclo es O (n). El tiempo de ejecución final es O (n log n).

+2

Tiene la idea correcta, pero se ha perdido un truco. (No publicarlo como respuesta porque el póster original solo quería una pista). Aquí hay una sugerencia para * usted * - vea cómo ordenar (1 8 9 7 6) con un costo de solo 41, no 42 :-) [Sugerencia: tiene que usar el 1 aunque esté en el lugar correcto.] – ShreevatsaR

+0

El caso 18976 presenta la excepción cubierta en mi solución, en el sentido de que un número "temp" suficientemente pequeño es más eficiente de usar para intercambiar otros números individualmente que usar un un número extra individual de un ciclo dos veces, en algunos casos. – Sparr

+1

También falla para 8 4 5 3 2 7 o incluso 3 1 2. Esta respuesta minimiza el número de intercambios, pero no las sumas. – xan

0

Como una pista, esto apesta a la programación dinámica; eso podría no ser lo suficientemente preciso como para ayudar, ¡pero prefiero comenzar con muy poco!

0

Se le cobra por el número de swaps, no por el número de comparaciones. Tampoco mencionaste que te cobraron por mantener otros registros.

1

Las comparaciones y recorridos aparentemente son gratuitos, puede precalcular la "distancia" que debe recorrer un número (y efectivamente el último orden de clasificación). El rompecabezas es el algoritmo de intercambio.

Minimizar intercambios generales es obviamente importante. También es importante minimizar los intercambios de números más grandes.

Estoy bastante seguro de que no se puede garantizar un proceso de intercambio óptimo mediante la evaluación de cada pedido de forma apátrida, aunque es posible que con frecuencia se acerque (no es el desafío).

3

Supongo que la memoria es libre y puede simular el orden antes de realizarla en los objetos reales.

Un enfoque (que probablemente no sea el más rápido) es mantener una cola de prioridad. Cada nodo en la cola está codificado por el costo de intercambio para llegar allí y contiene el orden actual de los elementos y la secuencia de pasos para lograr ese orden. Por ejemplo, inicialmente contendría un nodo de costo 0 con el ordenamiento de datos original y sin pasos.

Ejecute un ciclo que dequeue el elemento de cola de menor costo y encola todos los pasos de intercambio único posibles comenzando en ese punto. Sigue ejecutando el ciclo hasta que el jefe de la cola tenga una lista ordenada.

1

Creo que no hay una solución trivial a este problema, y ​​mi enfoque probablemente no sea mejor que el enfoque de cola de prioridad.

Encontrar el número más pequeño, N. Cualquier pares de números que ocupan ubicaciones deseadas de los demás deben intercambiarse, a excepción de N. Ensamble (por la fuerza bruta) una colección de cada conjunto de números que se pueden intercambiar mutuamente en sus ubicaciones deseadas, de modo que el costo de clasificar el conjunto entre ellos es menor que el costo de intercambiar cada elemento del conjunto con N. Estos conjuntos comprenderán una serie de ciclos. Cambie dentro de esos ciclos de tal manera que el número más pequeño se intercambie dos veces. Intercambia todos los números restantes, que comprenden un ciclo que incluye N, usando N como marcador de posición.

+0

Ya existe una solución aceptada que es más o menos la respuesta correcta; puede * demostrar * que (con la modificación obvia) es óptima."Reducir" algo a un problema NP-hard es demasiado fácil; eso no dice nada sobre la dureza del problema original: P – ShreevatsaR

+0

¿Por qué dices "ya" cuando publiqué el mío una hora antes de la respuesta aceptada? Ignorando por un momento que la respuesta aceptada es incorrecta. – Sparr

+0

Ya existe un contraejemplo a su hipótesis. Vea el análisis de Raymond. – recursive

2

I hicieron algunos intentos en la solución de uno de los ejemplos con la mano:

  • 6 8 9 7 1 (+ 6 + 1 = 7)
  • 6 8 1 7 9 (7 + 1 + 9 = 17)
  • 6 8 7 1 9 (17 + 1 + 7 = 25)
  • 6 1 7 8 9 (25 + 1 + 8 = 34)
  • 1 6 7 8 9 (34 + 1 + 6 = 41)

Como necesitaba desplazar el 1, parece que debe hacer una búsqueda exhaustiva para completar el problema, cuyos detalles ya fueron publicados por otro usuario. Tenga en cuenta que encontrará problemas si el conjunto de datos es grande al hacer este método.

Si el problema permite respuestas "cercanas", simplemente puede hacer un algoritmo codicioso que coloque el elemento más grande en su posición, ya sea directamente o intercambiando primero el elemento más pequeño en esa ranura.

Cuestiones relacionadas