Na semana passada, trabalhamos para criar a menor seqüência 1-D usando as 10.000 palavras mais usadas no idioma inglês . Agora, vamos tentar o mesmo desafio em 2D!
O que você precisa fazer é pegar todas as palavras acima e colocá-las em um retângulo o menor possível, permitindo sobreposições. Por exemplo, se suas palavras fossem ["ape","pen","ab","be","pa"]
, um possível retângulo seria:
.b..
apen
O retângulo acima daria uma pontuação de 5.
Regras:
- Sobreposição de várias letras em uma palavra é permitida
- As palavras podem seguir qualquer uma das 8 direções
- As palavras não podem ser contornadas
- Você pode usar qualquer caractere para os locais vazios
Você precisa criar uma pesquisa por palavras que contenha essas 10.000 palavras principais em inglês (de acordo com o Google). Sua pontuação é igual ao número de caracteres na sua pesquisa de palavras (excluindo caracteres não utilizados). Se houver um empate ou se for comprovado que um envio é o ideal, o envio publicado pela primeira vez vence.
fonte
Respostas:
Rust,
3143030081 caracteres usadosEsse é um tipo de algoritmo ganancioso: começamos com uma grade vazia e adicionamos repetidamente a palavra que pode ser adicionada com o menor número de novas letras, com os laços quebrados ao preferir palavras mais longas. Para fazer essa execução rapidamente, mantemos uma fila prioritária de posicionamentos de palavras candidatas (implementada como um vetor de vetores de deques, com um vetor para cada número de novas letras, contendo um deque para cada comprimento de palavra). Para cada carta adicionada recentemente, colocamos em fila todas as veiculações de candidatos que passam por essa carta.
Compile e execute com
rustc -O wordsearch.rs; ./wordsearch < google-10000-english.txt
. No meu laptop, isso é executado em 70 segundos, usando 531 MiB de RAM.A saída se encaixa em um retângulo com 248 colunas e 253 linhas.
Código
fonte
C ++, grade de 27243 caracteres (248x219, preenchido 50,2%)
(Postando isso como uma nova resposta, porque eu gostaria de manter o 1D vinculado que eu originalmente postei como referência)
Isso é
flagrantementeinspirado pela resposta de @ AndersKaseorg em sua estrutura principal, mas tem alguns ajustes. Primeiro, uso meu programa original para mesclar seqüências de caracteres até que a melhor sobreposição disponível seja de apenas 3 caracteres. Então eu uso o método que AndersKaseorg descreve para preencher progressivamente uma grade 2D usando essas seqüências de caracteres geradas. As restrições também são um pouco diferentes: ele ainda tenta adicionar o menor número de caracteres de cada vez, mas os vínculos são interrompidos favorecendo primeiro as grades quadradas, depois as pequenas e, finalmente, adicionando a palavra mais longa.O comportamento exibido é alternar entre períodos de preenchimento de espaço e expansão rápida da grade (infelizmente ficou sem palavras logo após um estágio de expansão rápida, para que haja muito espaço em branco nas bordas). Eu suspeito que, com alguns ajustes na função de custo, ela poderia ser melhorada do que 50% de preenchimento de espaço.
Existem 2 executáveis aqui (para evitar a necessidade de reexecutar todo o processo ao melhorar iterativamente o algoritmo). A saída de um pode ser canalizada diretamente para o outro:
E, finalmente, o resultado:
Resultado alternativo (depois de corrigir alguns bugs no programa que influenciavam certas direções e aprimoravam a função de custo, obtive uma solução mais compacta, mas menos otimizada): 29275 caracteres, 198x195 (preenchidos 75,8%):
Novamente, não fiz muito para otimizar esses programas, por isso leva um tempo. Mas você pode ver como ele preenche a grade, o que é bastante hipnótico.
fonte
C ++, grade de 34191 caracteres (com intervenção humana mínima, 6 ou 7 podem ser facilmente salvos)
Isso deve ser tomado mais como um limite para o caso 2D, porque a resposta ainda é uma string 1D. É apenas o meu código do desafio anterior, mas com a nova capacidade de reverter qualquer string. Isso nos dá muito mais espaço para combinar palavras (principalmente porque limita o pior caso de supercordas sem sobreposição a 26; um para cada letra do alfabeto).
Para um leve apelo visual em 2D, ele coloca quebras de linha no resultado, se puder fazê-lo gratuitamente (ou seja, entre palavras com sobreposição de 0).
Muito lento (ainda sem cache). Aqui está o código:
Resultado: http://pastebin.com/UTe2WMcz (4081 caracteres a menos que o desafio anterior)
É bastante claro que algumas economias triviais podem ser feitas colocando as linhas
xd
e nawv
vertical, cruzando a linha dos monstros. Entãohhidetautisbneudui
pode cruzar com od
, elxwwwowaxocnnaesdda
comw
. Isso salva 4 caracteres.nbcllilhn
pode ser substituído por umas
sobreposição existente (se for possível encontrar) para salvar outros 2 (ou apenas 1 se não existir essa sobreposição e, em vez disso, deve ser adicionada verticalmente). Finalmente,mjjrajaytq
pode ser adicionado verticalmente em algum lugar para salvar 1. Isso significa que, com mínima intervenção humana, 6 a 7 caracteres podem ser salvos no resultado.Gostaria de colocar isso em 2D com o seguinte método, mas estou lutando para encontrar uma maneira de implementá-lo sem criar o algoritmo O (n ^ 4), o que é bastante impraticável de calcular!
fonte
PHP
este faz o trabalho termoraticamente; mas 10000 provavelmente são muitas palavras para recursão. O script está sendo executado agora. (ainda funcionou 24 horas depois)
funciona bem em pequenos diretórios, mas posso fazer uma versão iterativa na próxima semana.
$f=array("pen","op","po","ne","pro","aaa","abcd","dcba"); will output
abcdalthough this is not an optimal result (scoring was changed ... I´m working on a generator). One optimal result is this:
openTambém não é muito rápido; remove apenas substrings e classifica os restos por comprimento,
o resto é força bruta: tente encaixar as palavras em um retângulo, tente um retângulo maior se falhar.
btw: A parte de substring precisa de 4,5 minutos na minha máquina para o diretório grande
e a reduz para 6.190 palavras; o tipo neles leva 11 segundos.
fonte