Escriba un programa para dibujar un diagrama 2D de un nudo basado en la estructura del nudo. Un nudo es exactamente lo que parece: un lazo de cuerda que está atado. En matemáticas, un diagrama de nudos muestra dónde un trozo de cuerda se cruza sobre o debajo de sí mismo para formar el nudo. A continuación se muestran algunos diagramas de nudos de ejemplo:
Hay una ruptura en la línea donde la cuerda se cruza sobre sí misma.
Entrada: la entrada que describe el nudo es una matriz de enteros. Un nudo donde la cuerda se cruza sobre sí misma n veces puede representarse como una matriz de n enteros, cada uno con un valor en el rango [0, n-1]. Vamos a llamar a esta matriz K .
Para obtener la matriz que describe un nudo, numere cada uno de los segmentos del 0 al n-1. El segmento 0 debería conducir al segmento 1, que debería conducir al segmento 2, que debería conducir al segmento 3, y así sucesivamente hasta que el segmento n-1 regrese y conduzca al segmento 0. Un segmento termina cuando otro segmento de cuerda lo cruza ( representado por un salto en la línea del diagrama). Tomemos el nudo más simple: el nudo trébol. Después de haber numerado los segmentos, el segmento 0 termina cuando el segmento 2 lo cruza; el segmento 1 termina cuando el segmento 0 lo cruza; y el segmento 2 termina cuando el segmento 1 cruza sobre él. Por lo tanto, la matriz que describe el nudo es [2, 0, 1]. En general, el segmento x comienza donde quedó el segmento x-1 mod n , y termina donde el segmento K [x] lo cruza.
La siguiente imagen muestra diagramas de nudos, con segmentos etiquetados y las matrices correspondientes que describen el nudo.
Los tres diagramas superiores son nudos verdaderos, mientras que los tres inferiores son bucles de cuerda que se cruzan sobre sí mismos pero que en realidad no están anudados (pero que todavía tienen los códigos correspondientes).
Su tarea es escribir una función que tome una matriz de enteros K (podría llamarse algo diferente) que describa un nudo (o lazo de cuerda que en realidad no está anudado), y que produzca el diagrama de nudos correspondiente, como se describe en el anterior ejemplos Si puede, proporcione una versión no codificada de su código o una explicación, y también proporcione resultados de muestra de su código. El mismo nudo a menudo se puede representar de múltiples maneras diferentes, pero si el diagrama de nudos que satisface su salida tiene la entrada como una de sus posibles representaciones, su solución es válida.
Este es el código de golf, por lo que gana el código más corto en bytes. La línea que representa la cuerda puede tener un grosor de 1 píxel, sin embargo, los cruces inferiores y superiores deben ser claramente distinguibles (el tamaño de la rotura de la cuerda debe ser mayor que el grosor de la cuerda en al menos un píxel a cada lado) .
Votaré las respuestas que se basan en las capacidades de la teoría de nudos incorporadas, pero la que se selecciona al final no puede confiar en las capacidades de la teoría de nudos incorporadas.
Todo lo que sé sobre mi notación: creo que hay secuencias de valores que no parecen corresponder a ningún nudo o nudo. Por ejemplo, la secuencia [2, 3, 4, 0, 1] parece ser imposible de dibujar.
Aparte de eso, suponga que toma un cruce y, a partir de ese cruce, siga el camino de la cuerda en una dirección y etiquete cada cruce sin etiquetar que encuentre con valores integrales sucesivamente mayores. Para nudos alternos, hay un algoritmo simple para convertir mi notación en tal etiquetado, y para nudos alternos es trivial convertir este etiquetado en un Código Gauss:
template<size_t n> array<int, 2*n> LabelAlternatingKnot(array<int, n> end_at)
{
array<int, n> end_of;
for(int i=0;i<n;++i) end_of[end_at[i]] = i;
array<int, 2*n> p;
for(int& i : p) i = -1;
int unique = 0;
for(int i=0;i<n;i++)
{
if(p[2*i] < 0)
{
p[2*i] = unique;
p[2*end_of[i] + 1] = unique;
++unique;
}
if(p[2*i+1] < 0)
{
p[2*i+1] = unique;
p[2*end_at[i]] = unique;
++unique;
}
}
return p;
}
template<size_t n> auto GetGaussCode(array<int, n> end_at)
{
auto crossings = LabelAlternatingKnot(end_at);
for(int& i : crossings) ++i;
for(int i=1;i<2*n;i+=2) crossings[i] = -crossings[i];
return crossings;
}
fuente
KnotData
en Mathematica ...: '(Knot
incorporado! Ejemplo de uso:<< Units`; Convert[Knot, Mile/Hour]
rendimientos1.1507794480235425 Mile/Hour
. (Creo que esto es divertido independientemente de si es verdadero o falso; pero en realidad es cierto.)Respuestas:
GNU Prolog,
622634668 bytes en la página de códigos 850Actualización : la versión anterior del programa a veces hacía cruces tan apretados que no se representaban correctamente, lo que viola las especificaciones. He agregado un código extra para evitar eso.
Actualización : Aparentemente, las reglas PPCG requieren un código adicional para que el programa salga y restaure el estado exactamente como estaba al principio. Esto hace que el programa sea algo más largo y no agrega ningún interés algorítmico, pero en aras del cumplimiento de las reglas, lo he cambiado.
Programa de golf
Usando GNU Prolog porque tiene una sintaxis de resolución de restricciones que es ligeramente más corta que la sintaxis aritmética de Prolog portátil, ahorrando unos pocos bytes.
Algoritmo
Este es uno de esos problemas en los que es difícil saber cómo comenzar. No es obvio cómo calcular la forma del nudo a partir de la notación dada, porque no le permite saber si está destinado a doblar la línea hacia la izquierda o hacia la derecha en un lugar determinado (y como tal, el la notación puede ser ambigua). Mi solución fue, efectivamente, utilizar el viejo modo de espera de golf: escribir un programa increíblemente ineficiente que genera todas las salidas posibles y luego ver si coinciden con la entrada. (El algoritmo utilizado aquí es un poco más eficiente, ya que Prolog puede arrojar un callejón sin salida ocasional, pero no tiene suficiente información para mejorar la complejidad computacional).
La salida es a través del terminal art. GNU Prolog parece querer un conjunto de caracteres de un solo byte que sea consistente con ASCII, pero no le importa cuál se use (ya que trata los caracteres con el conjunto de bits alto como opacos). Como resultado, utilicé IBM850, que es ampliamente compatible y tiene los caracteres de dibujo lineal que necesitamos.
Salida
El programa busca todas las imágenes de nudos posibles, en el orden del tamaño de su cuadro delimitador, luego sale cuando encuentra la primera. Así es como se ve la salida
m([0]).
:Esto tardó 290.528 segundos en ejecutarse en mi computadora; El programa no es muy eficiente. Lo dejé funcionando durante dos horas
m([0,1])
y terminé con esto:Versión sin golf con comentarios
El resaltador de sintaxis de Stack Exchange parece tener el símbolo de comentario incorrecto para Prolog, por lo que en lugar de
%
comentarios (que Prolog realmente usa), esta explicación usa% #
comentarios (que, por supuesto, son equivalentes debido a comenzar%
, pero resaltar correctamente).fuente