Este desafío es encontrar la cadena más larga de palabras en inglés donde los primeros 3 caracteres de la siguiente palabra coincidan con los últimos 3 caracteres de la última palabra. Utilizará un diccionario común disponible en distribuciones de Linux que se puede descargar aquí:
https://www.dropbox.com/s/8tyzf94ps37tzp7/words?dl=0
que tiene 99171 palabras en inglés. Si su Linux local/usr/share/dict/words
es el mismo archivo (tiene md5sum == cbbcded3dc3b61ad50c4e36f79c37084), puede usarlo.
Las palabras solo pueden usarse una vez en una respuesta.
EDITAR: letras deben coincidir exactamente incluyendo mayúsculas / minúsculas, apóstrofes y acentos.
Un ejemplo de una respuesta válida es:
idea deadpan panoramic micra craftsman mantra traffic fiche
que obtendría 8.
La respuesta con la cadena de palabras válida más larga será la ganadora. En caso de empate, la primera respuesta ganará. Su respuesta debe enumerar la cadena de palabras que ha encontrado y (por supuesto) el programa que escribió para hacerlo.
fuente
Respuestas:
Java, heurística que favorece el vértice que induce el gráfico más grande:
1825 18551873El siguiente código se ejecuta en menos de 10 minutos y encuentra la siguiente ruta:
Ideas centrales
En Aproximación de rutas y ciclos dirigidos más largos , Bjorklund, Husfeldt y Khanna, Lecture Notes in Computer Science (2004), 222-233, los autores proponen que en los gráficos de expansores dispersos se puede encontrar un largo camino mediante una búsqueda codiciosa que selecciona en cada pase al vecino de la cola actual de la ruta que abarca el subgrafo más grande en G ', donde G' es el gráfico original con los vértices en la ruta actual eliminados. No estoy seguro de una buena manera de probar si un gráfico es un gráfico expansor, pero ciertamente estamos tratando con un gráfico disperso, y dado que su núcleo tiene aproximadamente 20000 vértices y tiene un diámetro de solo 15, debe tener un buen propiedades de expansión Entonces adopto esta heurística codiciosa.
Dado un gráfico
G(V, E)
, podemos encontrar cuántos vértices son accesibles desde cada vértice usando Floyd-Warshall aTheta(V^3)
tiempo, o usando el algoritmo de Johnson aTheta(V^2 lg V + VE)
tiempo. Sin embargo, sé que estamos tratando con un gráfico que tiene un componente muy grande fuertemente conectado (SCC), por lo que adopto un enfoque diferente. Si identificamos SCCs utilizando el algoritmo de Tarjan, también obtenemos una clasificación topológica para el gráfico comprimidoG_c(V_c, E_c)
, que será mucho más pequeño en elO(E)
tiempo. ComoG_c
es un DAG, podemos calcular la accesibilidadG_c
aO(V_c^2 + E_c)
tiempo. (Posteriormente descubrí que esto se insinúa en el ejercicio 26-2.8 de CLR ).Como el factor dominante en el tiempo de ejecución es
E
, lo optimizo insertando nodos ficticios para los prefijos / sufijos. Entonces, en lugar de 151 * 64 = 9664 bordes de palabras que terminan -res a palabras que comienzan con res- Tengo 151 bordes de palabras que terminan -res a # res # y 64 bordes de # res # a palabras que comienzan con res- .Y finalmente, dado que cada búsqueda toma alrededor de 4 minutos en mi PC anterior, trato de combinar los resultados con rutas largas anteriores. Esto es mucho más rápido y apareció mi mejor solución actual.
Código
org/cheddarmonk/math/graph/Graph.java
:org/cheddarmonk/math/graph/MutableGraph.java
:org/cheddarmonk/math/graph/StronglyConnectedComponents.java
:org/cheddarmonk/ppcg/PPCG.java
:fuente
Rubí, 1701
"Del" -> "ersatz's"
( secuencia completa )Tratar de encontrar la solución óptima resultó demasiado costoso a tiempo. Entonces, ¿por qué no elegir muestras aleatorias, almacenar en caché lo que podamos y esperar lo mejor?
Primero
Hash
se construye un mapa que asigna prefijos a mundos completos comenzando con ese prefijo (por ejemplo"the" => ["the", "them", "their", ...]
). Luego, por cada palabra en la lista,sequence
se llama al método . Obtiene las palabras que posiblemente podrían seguir delHash
, toma una muestra de100
y se llama recursivamente. La más larga se toma y se muestra con orgullo. La semilla para el RNG (Random::DEFAULT
) y la longitud de la secuencia también se muestran.Tuve que ejecutar el programa varias veces para obtener un buen resultado. Este resultado particular se generó con semilla
328678850348335483228838046308296635426328678850348335483228838046308296635426
.Guión
fuente
0.0996
segundos.Puntuación:
16311662 palabrasPuede encontrar la secuencia completa aquí: http://pastebin.com/TfAvhP9X
No tengo el código fuente completo. Estaba probando diferentes enfoques. Pero aquí hay algunos fragmentos de código, que deberían ser capaces de generar una secuencia de aproximadamente la misma longitud. Lo siento, no es muy bonita.
Código (Python):
Primero, un preprocesamiento de los datos.
Luego definí una función recursiva (profundidad primera búsqueda).
Por supuesto, esto lleva demasiado tiempo. Pero después de un tiempo encontró una secuencia con 1090 elementos, y me detuve.
Lo siguiente que debe hacer es una búsqueda local. Para cada dos vecinos n1, n2 en la secuencia, trato de encontrar una secuencia que comience en n1 y termine en n2. Si existe tal secuencia, la inserto.
Por supuesto, también tuve que detener el programa manualmente.
fuente
PHP,
17421795He estado jugando con PHP en esto. El truco definitivamente es eliminar la lista de alrededor de 20k que son realmente válidos, y simplemente tirar el resto. Mi programa hace esto iterativamente (algunas palabras que arroja en la primera iteración significan que otras ya no son válidas) al comienzo.
Mi código es horrible, usa una serie de variables globales, usa demasiada memoria (guarda una copia de la tabla de prefijos completa para cada iteración) y me llevó literalmente días encontrar mi mejor versión actual, pero aún se las arregla estar ganando, por ahora. Comienza bastante rápido pero se vuelve más y más lento a medida que pasa el tiempo.
Una mejora obvia sería usar una palabra huérfana para el inicio y el final.
De todos modos, realmente no sé por qué mi lista de pastebin se movió a un comentario aquí, está de vuelta como un enlace a pastebin ya que ahora he incluido mi código.
http://pastebin.com/Mzs0XwjV
fuente
Python:
1702-1704 Artículos de- 1733 palabrasUsé un Dict para asignar todos los prefijos a todas las palabras, como
Edite una pequeña mejora: eliminar todas las
useless
palabras al principio, si sus sufijos no están en la lista de prefijos (obviamente sería una palabra final)Luego tome una palabra en la lista y explore el mapa de prefijos como un nodo de árbol
El programa necesita varias palabras para saber cuándo parar, se puede encontrar como
1733
en el métodocheckForNextWord̀
El programa necesita la ruta del archivo como argumento
No muy pitónico, pero lo intenté.
Se tardó menos de 2 minutos en calcular esta secuencia: salida completa :
fuente
Puntuación:
2495001001Aquí está mi código:
Editar: 1001:
http://pastebin.com/yN0eXKZm
Editar: 500:
fuente
Mathematica
14821655Algo para comenzar ...
Los enlaces son los prefijos y sufijos de intersección de palabras.
Los bordes son todos los enlaces dirigidos de una palabra a otras palabras:
Encuentre un camino entre "reparar" y "entusiasmo".
Resultado (1655 palabras)
fuente
Python, 90
Primero limpio la lista manualmente eliminando todos
esto me cuesta como máximo 2 puntos porque esas palabras solo pueden estar al principio o al final de la cadena, pero reduce la lista de palabras en 1/3 y no tengo que lidiar con unicode.
Luego construyo una lista de todos los pre y sufijos, encuentro la superposición y descarto todas las palabras a menos que tanto el pre como el sufijo estén en el conjunto de superposición. Nuevamente, esto reduce a lo sumo 2 puntos de mi puntaje máximo alcanzable, pero reduce la lista de palabras a un tercio del tamaño original (intente ejecutar su algoritmo en short_list para una posible aceleración) y las palabras restantes están altamente conectadas (excepto algunas 3 -cartas de palabras que están conectadas solo entre sí). De hecho, se puede llegar a casi cualquier palabra desde cualquier otra palabra a través de una ruta con un promedio de 4 bordes.
Almaceno el número de enlaces en una matriz de adyacencia que simplifica todas las operaciones y me permite hacer cosas interesantes como mirar pasos adelante o contar ciclos ... al menos en teoría, ya que toma alrededor de 15 segundos cuadrar la matriz que realmente no hago. esto durante la búsqueda. En cambio, comienzo con un prefijo aleatorio y camino al azar, ya sea eligiendo un final uniformemente, favoreciendo los que ocurren con frecuencia (como '-ing') o los que ocurren con menos frecuencia.
Las tres variantes apestan por igual y producen cadenas en un rango de 20-40, pero al menos es rápido. Supongo que debo agregar la recursión después de todo.
Originalmente quería probar algo similar a esto pero como se trata de un gráfico dirigido con ciclos, ninguno de los algoritmos estándar para la Clasificación topológica, la ruta más larga, la ruta euleriana más grande o el problema del cartero chino funciona sin grandes modificaciones.
Y solo porque se ve bien, aquí hay una imagen de la matriz de adyacencia M, M ^ 2 y M ^ infinito (infinito = 32, no cambia después) con entradas blancas = distintas de cero
fuente