Esse desafio é encontrar a cadeia mais longa de palavras em inglês, onde os 3 primeiros caracteres da próxima palavra correspondem aos 3 últimos da última palavra. Você usará um dicionário comum disponível nas distribuições Linux, que pode ser baixado aqui:
https://www.dropbox.com/s/8tyzf94ps37tzp7/words?dl=0
que possui 99171 palavras em inglês. Se o seu Linux local /usr/share/dict/words
for o mesmo arquivo (md5sum == cbbcded3dc3b61ad50c4e36f79c37084), você poderá usá-lo.
Palavras só podem ser usadas uma vez em uma resposta.
EDIT: As letras devem corresponder exatamente, incluindo maiúsculas / minúsculas, apóstrofos e acentos.
Um exemplo de resposta válida é:
idea deadpan panoramic micra craftsman mantra traffic fiche
qual seria a pontuação 8.
A resposta com a cadeia de palavras válida mais longa será a vencedora. Em caso de empate, a resposta mais rápida vencerá. Sua resposta deve listar a cadeia de palavras que você encontrou e (é claro) o programa que você escreveu para fazê-lo.
fonte
Respostas:
Java, heurística a favor do vértice que induz o maior gráfico:
1825 18551873O código abaixo é executado em menos de 10 minutos e encontra o seguinte caminho:
Idéias principais
Em Aproximando caminhos e ciclos diretos mais longos , Bjorklund, Husfeldt e Khanna, Lecture Notes in Computer Science (2004), 222-233, os autores propõem que, em gráficos esparsos de expansores, um caminho longo pode ser encontrado por uma pesquisa ambiciosa que seleciona a cada pise o vizinho da cauda atual do caminho que se estende pelo maior subgrafo em G ', onde G' é o gráfico original com os vértices no caminho atual excluídos. Não tenho certeza de uma boa maneira de testar se um gráfico é um gráfico expansor, mas certamente estamos lidando com um gráfico esparso, e como seu núcleo é de cerca de 20.000 vértices e tem um diâmetro de apenas 15, deve ter uma boa propriedades de expansão. Então, eu adoto essa heurística gananciosa.
Dado um gráfico
G(V, E)
, podemos encontrar quantos vértices são alcançáveis de cada vértice usando Floyd-Warshall noTheta(V^3)
tempo ou usando o algoritmo de Johnson noTheta(V^2 lg V + VE)
tempo. No entanto, eu sei que estamos lidando com um gráfico que tem um componente fortemente conectado (SCC) muito grande, por isso adoto uma abordagem diferente. Se identificarmos SCCs usando o algoritmo de Tarjan , também obteremos uma classificação topológica para o gráfico compactadoG_c(V_c, E_c)
, que será muito menor com oO(E)
tempo. ComoG_c
é um DAG, podemos calcular a acessibilidadeG_c
noO(V_c^2 + E_c)
tempo. (Descobri subseqüentemente que isso é sugerido no exercício 26-2.8 do CLR ).Como o fator dominante no tempo de execução é
E
, eu o otimizo inserindo nós fictícios para os prefixos / sufixos. Então, em vez de 151 * 64 = 9664 arestas das palavras que terminam -res em palavras que começam com res- Eu tenho 151 arestas das palavras que terminam -res para # res # e 64 arestas de # res # para palavras que começam com res- .E, finalmente, como cada pesquisa leva cerca de 4 minutos no meu PC antigo, tento combinar os resultados com caminhos longos anteriores. Isso é muito mais rápido e apareceu minha melhor solução atual.
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
:fonte
Ruby, 1701
"Del" -> "ersatz's"
( sequência completa )Tentar encontrar a solução ideal mostrou-se muito caro no tempo. Então, por que não escolher amostras aleatórias, armazenar em cache o que pudermos e esperar o melhor?
Primeiro
Hash
é construído um que mapeia prefixos para mundos completos, começando com esse prefixo (por exemplo"the" => ["the", "them", "their", ...]
). Então, para cada palavra da lista, o métodosequence
é chamado. Ele obtém as palavras que poderiam seguir a partir deHash
, pega uma amostra100
e se chama recursivamente. O mais longo é tirado e exibido com orgulho. As sementes do RNG (Random::DEFAULT
) e o comprimento da sequência também são exibidos.Eu tive que executar o programa algumas vezes para obter um bom resultado. Esse resultado específico foi gerado com sementes
328678850348335483228838046308296635426328678850348335483228838046308296635426
.Roteiro
fonte
0.0996
segundos.Pontuação:
16311662 palavrasVocê pode encontrar a sequência inteira aqui: http://pastebin.com/TfAvhP9X
Eu não tenho o código fonte completo. Eu estava tentando diferentes abordagens. Mas aqui estão alguns trechos de código que devem ser capazes de gerar uma sequência do mesmo tamanho. Desculpe, não é muito bonito.
Código (Python):
Primeiro, algum pré-processamento dos dados.
Depois, defini uma função recursiva (primeira pesquisa de profundidade).
Claro que isso leva muito tempo. Mas depois de algum tempo, ele encontrou uma sequência com 1090 elementos e eu parei.
A próxima coisa a fazer é uma pesquisa local. Para cada dois vizinhos n1, n2 na sequência, tento encontrar uma sequência começando em n1 e terminando em n2. Se existe uma sequência, insiro-a.
Claro que também tive que parar o programa manualmente.
fonte
PHP,
17421795Eu tenho mexido com PHP sobre isso. O truque é definitivamente selecionar a lista para os cerca de 20 mil que são realmente válidos e jogar o resto fora. Meu programa faz isso iterativamente (algumas palavras que ele joga fora na primeira iteração significa que outras não são mais válidas) no início.
Meu código é horrível, ele usa várias variáveis globais, usa muita memória (mantém uma cópia de toda a tabela de prefixos para cada iteração) e levou literalmente dias para chegar ao meu melhor atual, mas ainda gerencia para ganhar - por enquanto. Começa muito rapidamente, mas fica cada vez mais lento com o passar do tempo.
Uma melhoria óbvia seria usar uma palavra órfã para o início e o fim.
Enfim, eu realmente não sei por que minha lista de pastas foi movida para um comentário aqui, ela está de volta como um link para pastas, pois agora eu incluí meu código.
http://pastebin.com/Mzs0XwjV
fonte
Python:
1702-1704- 1733 palavrasEu usei um Dict para mapear todos os prefixos para todas as palavras, como
Edite pequenas melhorias: removendo todas as
useless
palavras no início, se seus sufixos não estiverem na lista de prefixos (obviamente seria uma palavra final)Em seguida, escolha uma palavra na lista e navegue no mapa de prefixos como um nó da árvore
O programa precisa de um número de palavras para saber quando parar, pode ser encontrado como
1733
no métodocheckForNextWord̀
O programa precisa do caminho do arquivo como argumento
Não é muito pitonico, mas tentei.
Demorou menos de 2 minutos para calcular esta sequência: saída completa :
fonte
Pontuação:
2495001001Aqui está o meu código:
Edição: 1001:
http://pastebin.com/yN0eXKZm
Edição: 500:
fonte
Mathematica
14821655Algo para começar ...
Os links são os prefixos e sufixos de interseção das palavras.
Arestas são todos os links direcionados de uma palavra para outras palavras:
Encontre um caminho entre "emendar" e "entusiasmo".
Resultado (1655 palavras)
fonte
Python, 90
Primeiro eu limpo a lista manualmente, excluindo tudo
isso me custa no máximo 2 pontos, porque essas palavras só podem estar no começo ou no final da cadeia, mas reduz a lista de palavras em 1/3 e não preciso lidar com o unicode.
Em seguida, construo uma lista de todos os pré e sufixos, encontro a sobreposição e descarto todas as palavras, a menos que o pré e o sufixo estejam no conjunto de sobreposições. Novamente, isso diminui no máximo 2 pontos da minha pontuação máxima alcançável, mas reduz a lista de palavras para um terço do tamanho original (tente executar o algoritmo na lista curta para uma possível aceleração) e as palavras restantes estão altamente conectadas (exceto cerca de 3 letras que estão conectadas apenas a si mesmas). De fato, quase qualquer palavra pode ser alcançada a partir de qualquer outra palavra por um caminho com uma média de 4 arestas.
Eu armazeno o número de links em uma matriz de adjacência, o que simplifica todas as operações e permite que eu faça coisas legais, como olhar n passos à frente ou contar ciclos ... pelo menos em teoria, já que leva cerca de 15 segundos para quadrar a matriz. isso durante a pesquisa. Em vez disso, começo com um prefixo aleatório e ando aleatoriamente, escolhendo um final uniformemente, favorecendo aqueles que ocorrem com freqüência (como '-ing') ou aqueles que ocorrem com menos frequência.
Todas as três variantes são iguais e produzem correntes na faixa 20-40, mas pelo menos são rápidas. Acho que tenho que adicionar recursão, afinal.
Originalmente, eu queria tentar algo semelhante a isso, mas como esse é um gráfico direcionado com ciclos, nenhum dos algoritmos padrão para Classificação Topológica, Caminho Mais Longo, Maior Caminho Euleriano ou Problema do Carteiro Chinês funciona sem grandes modificações.
E só porque parece bom, aqui está uma imagem da matriz de adjacência M, M ^ 2 e M ^ infinito (infinito = 32, depois não muda) com entradas brancas = diferentes de zero
fonte