Tarea
Debe escribir un programa o función en el idioma de su elección que cuente con precisión el número de ciclos terminales de un gráfico dirigido simple.
Este tipo particular de gráfico dirigido se representa como una matriz de n enteros, cada uno con un valor aleatorio elegido independientemente entre 1 yn (o 0 y n-1, si su idioma cuenta desde 0). El gráfico puede considerarse como flechas que apuntan desde un índice (nodo) a un índice que coincide con el valor encontrado en el índice inicial.
Su función debe ser capaz de aceptar gráficos grandes, hasta n = 1024, o cualquier tamaño entero más pequeño.
Ejemplo
Considere este gráfico para n = 10:
[9, 7, 8, 10, 2, 6, 3, 10, 6, 8]
El índice 1 contiene un 9, por lo que hay una flecha desde el índice 1 al índice 9. El índice 9 contiene un 6, por lo que hay una flecha 9 -> 6. El índice 6 contiene 6, que es un ciclo terminal, que apunta hacia sí mismo.
El índice 2 contiene un 7. El índice 7 contiene un 3. El índice 3 contiene un 8. El índice 8 contiene un 10. El índice 10 contiene un 8, entonces ese es un segundo ciclo terminal (8 -> 10 -> 8 -> 10, etc. )
Índice 4 -> 10, que ingresa al segundo ciclo terminal. Asimismo, indexe 5 -> 2 -> 7 -> 3 -> 8, que también es parte del segundo ciclo terminal.
En este punto, se han verificado todos los índices (nodos), se han seguido todas las rutas y se han identificado dos ciclos terminales únicos. Por lo tanto, la función debe devolver 2 , ya que ese es el número de ciclos terminales en este gráfico dirigido.
Puntuación
Apunte al código más pequeño, pero asegúrese de que cuente los ciclos de terminal correctamente. El código más corto después de 1 semana gana.
Casos de prueba
Aquí hay algunos casos de prueba para verificar la exactitud de su código. Si su idioma cuenta los índices de la matriz a partir de 0, por supuesto, debe restar 1 del valor de cada elemento de la matriz, para evitar un índice fuera de límite.
n = 32, 5 ciclos:
[8, 28, 14, 8, 2, 1, 13, 15, 30, 17, 9, 8, 18, 19, 30, 3, 8, 25, 23, 12, 6, 7, 19, 24, 17, 7, 21, 20, 29, 15, 32, 32]
n = 32, 4 ciclos:
[20, 31, 3, 18, 18, 18, 8, 12, 25, 10, 10, 19, 3, 9, 18, 1, 13, 5, 18, 23, 20, 26, 16, 22, 4, 16, 19, 31, 21, 32, 15, 22]
n = 32, 3 ciclos:
[28, 13, 17, 14, 4, 31, 11, 4, 22, 6, 32, 1, 13, 15, 7, 19, 10, 28, 9, 22, 5, 26, 17, 8, 6, 13, 7, 10, 9, 30, 23, 25]
n = 32, 2 ciclos:
[25, 23, 22, 6, 24, 3, 1, 21, 6, 18, 20, 4, 8, 5, 16, 10, 15, 32, 26, 25, 27, 14, 13, 12, 9, 9, 29, 8, 13, 31, 32, 1]
n = 32, 1 ciclo:
[6, 21, 15, 14, 22, 12, 5, 32, 29, 3, 22, 23, 6, 16, 20, 2, 16, 25, 9, 22, 13, 2, 19, 20, 26, 19, 32, 3, 32, 19, 28, 16]
n = 32, 1 ciclo:
[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7]
n = 1024, 6 ciclos:
[239, 631, 200, 595, 178, 428, 582, 191, 230, 551, 223, 61, 564, 463, 568, 527, 143, 403, 154, 236, 928, 650, 14, 931, 236, 170, 910, 782, 861, 464, 378, 748, 468, 779, 440, 396, 467, 630, 451, 130, 694, 167, 594, 115, 671, 853, 612, 238, 464, 771, 825, 471, 167, 653, 561, 337, 585, 986, 79, 506, 192, 873, 184, 617, 4, 259, 4, 662, 623, 694, 859, 6, 346, 431, 181, 703, 823, 140, 635, 90, 559, 689, 118, 117, 130, 248, 931, 767, 840, 158, 696, 275, 610, 217, 989, 640, 363, 91, 129, 399, 105, 770, 870, 800, 429, 473, 119, 908, 481, 337, 504, 45, 1011, 684, 306, 126, 215, 729, 771, 5, 302, 992, 380, 824, 868, 205, 807, 917, 407, 759, 181, 640, 685, 795, 258, 180, 900, 20, 773, 546, 866, 564, 761, 632, 895, 968, 980, 651, 225, 676, 18, 685, 784, 208, 227, 3, 267, 852, 57, 487, 566, 633, 849, 309, 543, 145, 575, 811, 621, 560, 492, 24, 665, 66, 851, 168, 262, 259, 754, 481, 565, 768, 172, 1012, 241, 3, 370, 985, 389, 82, 779, 744, 829, 836, 249, 975, 909, 840, 226, 867, 499, 192, 909, 972, 735, 252, 785, 545, 486, 186, 1011, 89, 939, 649, 110, 119, 185, 836, 717, 545, 938, 621, 946, 94, 363, 721, 177, 747, 59, 819, 146, 283, 821, 547, 654, 941, 755, 18, 449, 367, 499, 944, 62, 553, 435, 344, 900, 25, 251, 920, 902, 99, 326, 98, 495, 385, 929, 865, 327, 725, 674, 33, 173, 429, 873, 558, 90, 460, 366, 543, 583, 954, 792, 213, 536, 670, 49, 738, 802, 1015, 23, 915, 119, 263, 307, 601, 474, 971, 826, 613, 446, 37, 145, 894, 901, 307, 906, 886, 990, 89, 798, 384, 487, 822, 354, 768, 902, 163, 179, 134, 920, 439, 619, 215, 94, 709, 744, 366, 543, 349, 347, 2, 438, 141, 486, 19, 998, 500, 857, 955, 932, 1, 587, 195, 646, 550, 887, 626, 400, 348, 154, 808, 678, 873, 186, 282, 168, 993, 722, 56, 345, 5, 226, 328, 22, 894, 658, 264, 13, 803, 791, 359, 217, 997, 168, 578, 952, 734, 964, 898, 659, 628, 980, 15, 31, 439, 13, 875, 687, 1004, 1023, 165, 642, 561, 897, 711, 124, 404, 346, 723, 774, 352, 784, 276, 395, 14, 443, 343, 153, 510, 590, 172, 215, 130, 106, 295, 906, 133, 758, 483, 898, 391, 760, 702, 972, 721, 611, 592, 1001, 724, 934, 59, 831, 171, 253, 869, 431, 538, 20, 648, 76, 351, 103, 33, 385, 852, 437, 470, 95, 434, 408, 430, 994, 366, 706, 809, 532, 161, 388, 668, 245, 965, 365, 913, 471, 927, 245, 256, 805, 540, 380, 995, 446, 657, 545, 573, 955, 499, 322, 949, 635, 401, 185, 421, 626, 534, 429, 930, 633, 563, 348, 626, 518, 682, 233, 775, 444, 42, 199, 57, 271, 683, 397, 883, 620, 768, 8, 331, 497, 19, 340, 900, 919, 497, 276, 78, 252, 164, 764, 927, 242, 270, 759, 824, 945, 886, 262, 59, 439, 217, 720, 519, 862, 626, 326, 339, 589, 16, 565, 947, 604, 144, 87, 520, 256, 240, 336, 685, 361, 998, 805, 678, 24, 980, 203, 818, 855, 85, 276, 822, 183, 266, 347, 8, 663, 620, 147, 189, 497, 128, 357, 855, 507, 275, 420, 755, 131, 469, 672, 926, 859, 156, 127, 986, 489, 803, 433, 622, 951, 83, 862, 108, 192, 167, 862, 242, 519, 574, 358, 549, 119, 630, 60, 925, 414, 479, 330, 927, 94, 767, 562, 919, 1011, 999, 908, 113, 932, 632, 403, 309, 838, 341, 179, 708, 847, 472, 907, 537, 516, 992, 944, 615, 778, 801, 413, 653, 690, 393, 452, 394, 596, 545, 591, 136, 109, 942, 546, 57, 626, 61, 587, 862, 829, 988, 965, 781, 849, 843, 815, 60, 928, 784, 388, 341, 491, 565, 83, 110, 164, 38, 1024, 859, 297, 520, 327, 733, 699, 631, 78, 178, 671, 895, 818, 637, 99, 425, 933, 248, 299, 333, 144, 323, 105, 849, 942, 767, 265, 72, 204, 547, 934, 916, 304, 919, 273, 396, 665, 452, 423, 471, 641, 675, 60, 388, 97, 963, 902, 321, 826, 476, 782, 723, 99, 735, 893, 565, 175, 141, 70, 918, 659, 935, 492, 751, 261, 362, 849, 593, 924, 590, 982, 876, 73, 993, 767, 441, 70, 875, 640, 567, 920, 321, 46, 938, 377, 905, 303, 736, 182, 626, 899, 512, 894, 744, 254, 984, 325, 694, 6, 367, 532, 432, 133, 938, 74, 967, 725, 87, 502, 946, 708, 122, 887, 256, 595, 169, 101, 828, 696, 897, 961, 376, 910, 82, 144, 967, 885, 89, 114, 215, 187, 38, 873, 125, 522, 884, 947, 962, 45, 585, 644, 476, 710, 839, 486, 634, 431, 475, 979, 877, 18, 226, 656, 573, 3, 29, 743, 508, 544, 252, 254, 388, 873, 70, 640, 918, 93, 508, 853, 609, 333, 378, 172, 875, 617, 167, 771, 375, 503, 221, 624, 67, 655, 465, 272, 278, 161, 840, 52, 1016, 909, 567, 544, 234, 339, 463, 621, 951, 962, 1019, 383, 523, 279, 780, 838, 984, 999, 29, 897, 564, 762, 753, 393, 205, 31, 150, 490, 156, 796, 586, 676, 773, 465, 489, 1024, 433, 214, 701, 480, 604, 280, 241, 563, 943, 911, 12, 400, 261, 883, 999, 207, 618, 141, 959, 767, 978, 461, 992, 982, 272, 143, 404, 645, 331, 348, 783, 698, 827, 82, 145, 536, 449, 852, 750, 789, 413, 913, 420, 14, 499, 285, 533, 223, 75, 591, 994, 884, 237, 63, 411, 563, 611, 801, 173, 759, 278, 318, 772, 1018, 48, 440, 333, 611, 834, 423, 583, 22, 716, 393, 794, 83, 83, 864, 859, 600, 525, 808, 569, 95, 952, 852, 567, 651, 2, 984, 906, 992, 747, 602, 143, 547, 1008, 940, 245, 633, 378, 193, 771, 965, 648, 437, 873, 591, 664, 271, 777, 274, 742, 68, 429, 825, 144, 55, 272, 279, 6, 400, 485, 66, 311, 663, 441, 23, 988, 726, 48, 624, 302, 617, 120, 653, 810, 641, 142]
fuente
Respuestas:
GolfScript, 25 caracteres
El mismo enfoque que la solución de Keith Randall pero en GolfScript. Tenga en cuenta que GolfScript tiene matrices indexadas a cero. Probador en línea .
fuente
Mathematica 69
Código
Esto encuentra el número de componentes del gráfico.
El primer caso de prueba:
Análisis
Haga una lista de aristas dirigidas entre índices (con el ejemplo 1).
Graph
dibuja un gráfico que muestra los componentes del gráfico.ImagePadding
yVertexLabels
se usan aquí para mostrar los índices.WeaklyConnectedComponents
devuelve la lista de vértices para cada componente.Length
Devuelve el número de componentes.Momento de la lista de muestra con 1024 elementos:
Tiempo: 0.002015 seg.
Solo por diversión, aquí hay una foto del caso de prueba final, graficado. Omití las etiquetas de vértice; hay demasiados.
fuente
WeaklyConnectedComponents
Es muy detallado. Pero hace mucho trabajo. (Uno nunca debe subestimar J y lenguajes similares por concisión.)Python,
132116 caracteresPara cada índice, seguimos los bordes de n saltos, lo que garantiza que estamos en un ciclo terminal. Luego seguimos n más saltos y encontramos el índice mínimo en ese ciclo. El número total de ciclos terminales es entonces el número de mínimos diferentes que encontramos.
fuente
#define F for i in r
en Python, C (++) - estilo ... :)En Python:
fuente
if
condiciones.c=lambda l:0 if l==[] else c(l[:-1])+1 if l[-1]==len(l) else c([[x,l[-1]][x==len(l)] for x in l[:-1]])
es mejor: 102 bytes.J -
6153 charEste fue un doozy.
Luego,
<@<:
convierte la lista en un gráfico J, que parece una lista de cuadros, y el cuadro en el índicei
contiene todos los nodos a los que sei
conecta el nodo . J indexa desde cero, por lo que usamos<:
para disminuir todo en uno antes de boxear con<
.La
<~.@(],;@:{~)^:_&.>]
gira cada nodo en una lista de todos los nodos que se pueden alcanzar de ella. El<...&.>]
es responsable de hacer que esto suceda a cada nodo, y en~.@(],;@:{~)^:_
realidad proviene de un golf J de esta tarea de 'nodos accesibles' que hice hace un par de semanas.e.
realiza una tarea interesante Si el cierre de "accesibilidad" del gráfico (la versión del gráfico es tal que si hay bordes dirigidos X → Y e Y → Z agregamos el borde X → Z.) Tiene N nodos y bordes E, entoncese.
en este gráfico una matriz booleana de N filas y columnas E, con True si el nodo correspondiente comparte un nodo accesible con este borde. Confuso, pero ten paciencia conmigo.Luego, tenemos que encontrar el número de ciclos terminales, es decir, el número de grupos que comparten Trues entre sus columnas. Queremos hacer una especie de tabla de multiplicación de las filas (
"1/~
), y usamos un tipo de producto interno como la multiplicación, uno que ANDs en pares y luego ORs todos los resultados juntos (+./ .*
). La matriz resultante es una tabla cuadrada con un Verdadero en cada posición en la que dos filas comparten al menos una columna entre ellas.Ahora todo lo que queda por hacer es verificar cuántos tipos diferentes de patrones de fila hay. Así que hacemos exactamente eso: agrupar filas del mismo tipo (
/.~
), informar el número en cada grupo (#
) y luego tomar el número de grupos (#@
).Uso en otros ejemplos:
Desafortunadamente, el caso de 1024 elementos ahora tarda mucho tiempo en terminar. La versión anterior
<:@#@((#~0={.+/@:*"1])^:a:)@e.@(~.@(],;@:{~)^:_&.>~<)@:(<@<:)
(61 caracteres) tardó un poco más de un segundo en hacer esto.fuente
Pitón (96)
Muy, muy, muy, muy basado en la respuesta del usuario 2228078, ya que funciona exactamente igual, pero tiene más golf:
(Pregunta técnica: ¿debería una respuesta de golf de alguien más ser un wiki comunitario?)
fuente
Pitón
(89)(87)La idea principal es comenzar en cada nodo a la vez y caminar a lo largo del camino desde él, marcando cada nodo que visitamos con una etiqueta única para el nodo en el que comenzamos. Si alguna vez golpeamos un nodo marcado, dejamos de caminar y verificamos si la marca es la que corresponde a nuestro nodo inicial. Si es así, debemos haber recorrido un ciclo, por lo que incrementamos el conteo de ciclos en uno.
En el código,
u
es el contador de ciclos,i
es el nodo inicial,j
es el nodo actual que estamos caminando. La etiqueta correspondiente al nodo iniciali
es su complemento de bits~i
que siempre es negativo. Marcamos un nodo señalándolo a ese valor, sobrescribiendo el nodo al que realmente señaló (teniendo cuidado de caminar hacia ese nodo antes de que se olvide).Sabemos que hemos alcanzado un nodo marcado cuando caminamos hacia un "nodo" de valor negativo inmediatamente después. Verificamos si ese valor negativo es la etiqueta actual para ver si hemos recorrido un ciclo. Como cada nodo que caminamos se elimina efectivamente, cada ciclo solo se caminará una vez.
Guarda los caracteres para contarlos
i
manualmente con una variable de bucle ficticio y_
luego comofor i in range(len(G))
. Las listas de Python están indexadas en 0. Si en su lugar estuvieran indexados en 1, podríamos guardar dos caracteres escribiendoj=i=i+1
para teneri
yj
ser 1 para el primer bucle, y escribirj>0
en lugar dej>=0
.Editar:
Podemos guardar dos caracteres iterando
i
sobre los elementos de la lista en lugar de los índices, ya que los nodos a los que no apunta ningún borde no importan. Sinset(G)
embargo, tenemos que iterar para evitar repetir un nodo de inicio al que apuntaron varios otros nodos.fuente