¿Cuál es el algoritmo más complicado por el que has pasado?

Mi respuesta va a ser un poco cuestionable cuando se trata del aspecto “complicado” de las cosas. Obviamente, los algoritmos “más engañosos” que he intentado descubrir son los que nunca logré descubrir cómo implementar, y nadie más lo ha hecho todavía.

Como realmente no sé cómo adivinar lo que la pregunta considera “difícil”, responderé con el algoritmo que me llevó más tiempo entender, aunque podría considerar que esto es una trampa.

Cuando estaba en octavo grado, estaba estudiando matemáticas de noveno grado por mi cuenta para no tener que dejar atrás a mis amigos para ir a la escuela secundaria. Mi maestra me daría un proyecto y luego se iría a enseñar al resto de la clase.

El siguiente tema resultó ser la programación lineal, que generalmente se enseña a ese nivel completamente sin matrices, pero ella solo me dijo que revisara esta explicación y la aplicación Java que demostraba el algoritmo simplex.

Fue mucho a la vez. Realmente no me había familiarizado demasiado con las matrices. La explicación fue muy detallada sobre la transformación del LP en una matriz, seleccionando pivotes, cómo transformar el estado, y así sucesivamente, y después de llevar la tarea a casa y pasar toda la noche jugando con ella y estudiándola, pude menos replicar el comportamiento del algoritmo a mano.

En este punto, realmente sabía muy poco sobre programación de computadoras, así que eso era lo mejor que podía hacer. Y la maestra simplemente dijo: “¡Oh, solo quería que reconocieras cómo usar las matrices y supieras qué era un programa lineal, todo esto era innecesario!”

Entonces, puse el algoritmo durante una década, y mientras tanto aprendí una o dos cosas sobre la idea de algoritmos y programas. Aprendí lo que realmente era un programa lineal. Tomé un par de clases y aprendí álgebra lineal.

Y luego Nemirovski me explicó el algoritmo simplex. Toda la idea intuitiva de ello. Por qué tiende a funcionar bastante bien solo siguiendo los bordes del politopo de nodo a nodo. Por qué es realmente malo en el peor de los casos. Sin embargo, por qué suele ser mejor que el método elipsoide.

Creo que, en este punto, si tuviera que dedicarle un poco de tiempo, podría implementar el algoritmo Simplex con un poco de revisión. Afortunadamente, nunca tendré que hacerlo.

Algoritmo de Ukkonen

Algoritmo del árbol de sufijos de Ukkonen en inglés simple

El algoritmo es para construir un árbol de sufijos en tiempo lineal. Ingenuamente, para una cadena de longitud [matemática] n [/ matemática], dicha estructura de datos ocuparía espacio O ([matemática] n ^ 2 [/ matemática]), y se representaría como un árbol donde se etiqueta cada borde con una copia de la cadena que representa. Con esta representación, parecería que el tiempo de ejecución de límite inferior de un algoritmo para construir un árbol de sufijos también sería cuadrático.

Sin embargo, resulta que puede usar una representación más compacta de un árbol de sufijos. La observación principal es que un borde no necesita copiar sobre subconjuntos de la cadena original. En su lugar, simplemente puede usar dos punteros en la cadena original, uno apuntando al comienzo del sufijo y otro apuntando al final. Como resultado, cada borde consume espacio constante.

Con esta representación, puede crear un árbol de sufijos en el tiempo O ([matemáticas] n [/ matemáticas]), y creo que el árbol de sufijos resultante también ocuparía espacio O ([matemáticas] n [/ matemáticas]).

Todavía no entiendo el algoritmo al 100%, y no lo he implementado. Sin embargo, debido a cómo se usan los punteros de forma no intuitiva, diría que este algoritmo es uno de los más complicados que he visto.

Podría decir que era AVL equilibrando un árbol ordenado. Sugerencia: nunca intente recrear un algoritmo que implique mover punteros utilizando pines de mapa y bandas elásticas. Terminé con un pin de mapa en posición vertical en mi pulgar después de que una banda elástica demasiado estirada me disparó.

Pero eso fue doloroso, más que complicado. Creo que este toma el premio como el más alucinante: convertir las fechas gregorianas en números de días julianos. Es increíblemente útil si necesita trabajar con fechas y períodos entre ellas, pero hacerlo de manera eficiente (esto fue para el registro de datos con miles de muestras por segundo) requiere que aprenda demasiado sobre cómo funciona nuestro calendario y los patrones ocultos. dentro de ella.

Double DayNumber (int día, int mes, int año)
{
largo a, b, c;
si (mes> 2)
{
mes – = 3;
}
más
{
mes + = 9;
año – = 1;
}
a = ((año% 100) * 1461) / 4;
b = ((año / 100) * 146097) / 4;
c = (mes * 153 + 2) / 5;
devuelve a + b + c + día + 1721118.5;
}

Fecha nula (número de día doble, int * día, int * mes, int * año)
{
largo r, a, siglos, pentdays, quarterdays, años;
quarterdays = ((int) (número de día – 1721118.5)) * 4 – 1;
r = cuartos de semana% 146097;
siglos = cuartos de semana / 146097;
a = (r / 4) * 4 + 3;
r = a% 1461;
años = a / 1461;
pentdays = (r / 4) * 5 + 2;
* mes = pentdays / 153;
pentdays = pentdays% 153;

* día = pentdays / 5 + 1;
* año = (siglos * 100) + años;
si (* mes <10)
{
* mes + = 3;
}
más
{
* mes – = 9;
* año + = 1;
}
}

Ahora, como programador serio, veo los muchos enteros literales en eso y se estremece. El problema es que para corregirlo, necesitaría definir constantes como esta.

#define DAYS_IN_400_YEARS 146097
#define DAYS_IN_FOUR_YEARS_ASSUMING_CENTURIES_ARE_LEAP_YEARS 1461
#define DAYS_IN_FIVE_MONTHS_ASSUMING_THEYRE_THE_RIGHT_FIVE_MONTHS 153
#define JULIAN_DAY_FOR_1ST_MARCH_1BC_IF_THE_GREGORIAN_CALENDAR_HAD_BEEN_USED_THEN 1721118.5

Equilibrio del árbol rojo-negro.

Los códigos de corrección de errores me sorprenden. Puedo entenderlos cuando un gran maestro me lo explica de manera competente, pero lo olvido en una semana. Son geniales