Dejemos que n sea el tamaño de la entrada, es decir, el número de dígitos de la entrada en alguna base, o la suma o el máximo de los logaritmos de las magnitudes de los números de la entrada-- todos ellos son equivalentes a efectos de big-O.
Estrategia: aplicar como máximo O(n) (transformaciones lineales que preservan el área dejando un eje de coordenadas fijo) a obtener un problema fácil, resolver el problema fácil, y luego aplicar la secuencia inversa de cizallas para obtener la solución de nuevo en el espacio de coordenadas original. en el espacio de coordenadas original.
PROBLEMA FÁCIL #1: cuando al menos uno de los dos rayos delimitadores está alineado con el eje.
PROBLEMA FÁCIL #2: cuando las dos direcciones de los rayos delimitadores apuntan a los interiores de diferentes cuadrantes del plano.
Se omiten los detalles de los problemas fáciles, ya que son sencillos y no son la parte interesante o desafiante de este problema.
Supongamos que tenemos un caso no fácil del problema: es decir, ambas direcciones de los rayos delimitadores apuntan al interior del mismo cuadrante; con el fin de que ambas apunten al primer cuadrante.
Elija uno de los dos rayos delimitadores y llámelo "primario" y el otro "secundario". Si el rayo primario tiene pendiente <1 , intercambia los ejes de coordenadas, de modo que la semirrecta primaria tenga pendiente ≥1 .
Dejemos que a/b≥1 sea la pendiente del rayo delimitador primario, con a≥b>0 tomado directamente de las ecuaciones de entrada. Sea q,r sea el cociente y el resto de la división de a por b . Es decir, q=floor(a/b),r=a−qb,a≥b>r≥0 .
Aplicar a la geometría del problema el cizallamiento que deja la y eje fijo y toma (1,q) à (1,0) ; en otras palabras, la transformación lineal que deja (0,1) fija y toma (1,0) à (1,−q) . Mantenga la designación "primario" en la imagen del rayo delimitador primario. Esta transformación de cizalladura disminuye la pendiente del rayo primario a r/b, manteniendo su dirección en el primer cuadrante (si r>0 ), o en paralelo a la x eje (si r=0 ).
Obsérvese que la solución antes de esta transformación de cizalla puede describirse mediante cualquiera de las siguientes caracterizaciones equivalentes (equivalentes porque ambos dirs de rayos delimitadores apuntan al primer cuadrante):
- (a) "el punto entero del trimestre más cercano al punto de intersección" (por definición)
- (b) "el punto entero del trimestre con el mínimo x+y ",
- (c) "el punto entero del trimestre con el mínimo x entre todos los puntos con un mínimo de y ".
- (d) "el punto entero del trimestre con el mínimo y entre todos los puntos con un mínimo de x "
Hay tres casos.
Caso 1: Tras el cizallamiento, ambos rayos siguen apuntando al interior del primer cuadrante.
En este caso, la solución del problema cizallado es, de nuevo, las siguientes caracterizaciones equivalentes:
- (a') "el punto entero del cuarto transformado más cercano al punto de intersección transformado"
- (b') "el punto entero del cuarto transformado con el mínimo x+y "
- (c') "el punto entero del cuarto transformado con el mínimo x entre todos los puntos con un mínimo de y ".
- (d') "el punto entero del cuarto transformado con el mínimo y entre todos los puntos con un mínimo de x "
Centrándonos en (d) y (d') queda claro que la solución del problema transformado es la solución transformada del problema original.
En el problema transformado, el rayo delimitador primario tiene pendiente r/b con b>r>0 (todavía en el caso 1 aquí) por lo que su pendiente es <1 ; Por lo tanto, al comenzar el análisis del problema transformado como antes, intercambiaremos las coordenadas para que su pendiente b/r>1 . Observe que lo que hemos hecho hasta ahora es realizar una iteración del algoritmo euclidiano es decir, a ha sido sustituido por b y b ha sido sustituido por el resto de a dividido por b .
Repetir tantas veces como nos encontremos en el caso 1 (manteniendo la designación "primaria" en el mismo de los dos rayos aunque se transformen). Dado que el a,b siguen los valores euclidianos comenzando con dos de los números de entrada originales, el conocido análisis del algoritmo euclidiano nos dice que el caso 1 puede ocurrir como máximo O(n) veces: es decir, si llegamos hasta el final del algoritmo euclidiano, b se convertirá en 0, lo que nos sacará del caso 1 (si es que no lo hemos dejado ya antes).
Caso 2: La cizalla hace que el rayo delimitador primario sea horizontal, y el rayo secundario cizallado sigue apuntando al primer cuadrante.
Exactamente igual que en el caso 1, (a')=(b')=(c')=(d') y, por tanto, la solución del problema transformado es la transformación de la solución del problema original. Además, el problema transformado es ahora un caso del PROBLEMA FÁCIL Nº 1; resuelva eso, transforme inversamente la solución de vuelta al espacio original; hecho. (Cuando esto se encuentra recursivamente desde el caso 1, significa que hemos llegado hasta el final del algoritmo euclidiano).
Caso 3: La cizalla lleva la dirección del rayo delimitador secundario fuera del interior del primer cuadrante, hacia el x eje o el cuarto cuadrante. (Esto es independiente de si la dirección del rayo delimitador primario se convirtió en horizontal o se mantuvo en el primer cuadrante).
Este caso es relativamente fácil de resolver, pero tenemos que tener cuidado en este caso la transformada del punto dentro del cuarto más cercano a la intersección (es decir, que satisface (a)) es no necesariamente el punto del cuarto transformado más cercano a la intersección transformada (es decir, que satisface (a')). Sin embargo es cierto que la transformada del punto que satisface (d) es el punto que satisface (d'). Por tanto, el problema de la transformada, aunque fácil, es no en la forma del problema original. En cambio, es un caso de:
PROBLEMA FÁCIL #3: Las direcciones de los rayos delimitadores apuntan ambas al semiplano +x, pero hacen no ambos apuntan al interior del mismo cuadrante, y se nos pide que encontremos el punto que satisface (d) en lugar de (a) (que son no necesariamente el mismo en este caso).
Así que he descrito un algoritmo para transformar el problema original en uno de los tres problemas fáciles, en O(n) iteraciones.
Análisis de la complejidad
El número de iteraciones es O(n) por lo que el tiempo total de ejecución es O(n) veces el coste por iteración.
¿Cuánto cuesta una iteración? Cada iteración consiste en un pequeño número constante de operaciones aritméticas, cada una de las cuales es como máximo O(M(num digits in operands)) donde M significa el coste de una multiplicación (véase el artículo de la wikipedia " Coste computacional de las operaciones matemáticas "). Pero, ¿cuántos dígitos son?
Pues bien, a primera vista parece que los valores intermedios y finales podrían tener hasta n2 dígitos, lo que haría que el tiempo total de ejecución O(nM(n2))) . Además, se puede sospechar que el n -El punto testigo de un dígito podría ayudar a disminuir este límite. Pero el siguiente análisis más detallado revela que no es tan malo, y que el n -El testigo de un dígito en realidad no hace ninguna diferencia.
Cada transformación es una cizalla seguida de un cambio de eje de coordenadas: (0110)(10−qi1)=(−qi110) donde q0,q1,... es la secuencia de cocientes q que se produce en el algoritmo euclidiano (posiblemente cortado por el caso 3). Así que la norma matricial de la matriz acumulativa es ≤ el producto de la qi 's, que es como máximo el valor original de a que tiene n dígitos. Y lo mismo puede decirse de la matriz inversa acumulativa. Eso nos dice que el número máximo de dígitos que aparecen en la respuesta o en cualquier valor intermedio es O(n) . Por lo tanto, el tiempo de ejecución total es O(nM(n)) .
Por cierto, la secuencia de cálculos de matrices enteras de 2x2 que se sigue es en realidad bien conocida como el EEA (Algoritmo Euclidiano Extendido) para el CRT (Teorema Chino del Resto). Si se lleva hasta el final la matriz acumulativa representa una transformación lineal invertible con coeficientes enteros que lleva la dirección del rayo primario original a un eje de coordenadas que puede ser un bloque de construcción útil para muchas aplicaciones (en particular, los problemas del Proyecto Euler :-) ). Así que uno podría pensar que podríamos simplemente usar una implementación preempacada de AEE como bloque de construcción; pero no veo cómo hacer que eso funcione para este problema, debido a la posibilidad de tener que parar antes de tiempo debido al caso 3.