La semaine dernière, nous avons travaillé à créer la chaîne 1D la plus courte en utilisant les 10 000 premiers mots de la langue anglaise . Maintenant, essayons le même défi en 2D!
Ce que vous devez faire est de prendre tous les mots ci-dessus et de les placer dans un rectangle aussi petit que possible, en tenant compte des chevauchements. Par exemple, si vos mots l'étaient ["ape","pen","ab","be","pa"]
, alors un rectangle possible serait:
.b..
apen
Le rectangle ci-dessus donnerait un score de 5.
Règles:
- Le chevauchement de plusieurs lettres dans un mot est autorisé
- Les mots peuvent aller dans l'une des 8 directions
- Les mots ne peuvent pas se terminer
- Vous pouvez utiliser n'importe quel caractère pour les emplacements vides
Vous devez créer une recherche de mots qui contient ces 10 000 premiers mots en anglais (selon Google). Votre score est égal au nombre de caractères dans votre recherche de mots (hors caractères non utilisés). S'il y a égalité ou si une soumission s'avère optimale, alors la soumission qui est publiée en premier l'emporte.
la source
Réponses:
Rust,
3143030081 caractères utilisésC'est un algorithme gourmand en quelque sorte: nous commençons avec une grille vide, et nous ajoutons à plusieurs reprises le mot qui peut être ajouté avec le moins de nouvelles lettres, avec des liens rompus en préférant des mots plus longs. Pour que cela fonctionne rapidement, nous maintenons une file d'attente prioritaire de placements de mots candidats (implémentée comme un vecteur de vecteurs de deques, avec un vecteur pour chaque nombre de nouvelles lettres, contenant un deque pour chaque longueur de mot). Pour chaque lettre nouvellement ajoutée, nous mettons en file d'attente tous les placements candidats qui traversent cette lettre.
Compilez et exécutez avec
rustc -O wordsearch.rs; ./wordsearch < google-10000-english.txt
. Sur mon ordinateur portable, cela fonctionne en 70 secondes, en utilisant 531 Mo de RAM.La sortie tient dans un rectangle avec 248 colonnes et 253 lignes.
Code
la source
C ++, grille de 27243 caractères (248 x 219, rempli à 50,2%)
(Publier ceci comme une nouvelle réponse parce que je voudrais garder la borne 1D que j'ai initialement publiée comme référence)
Cette
arnaque flagranteest fortement inspirée par la réponse de @ AndersKaseorg dans sa structure principale, mais a quelques ajustements. Tout d'abord, j'utilise mon programme d'origine pour fusionner des chaînes jusqu'à ce que le meilleur chevauchement disponible ne soit que de 3 caractères. Ensuite, j'utilise la méthode décrite par AndersKaseorg pour remplir progressivement une grille 2D en utilisant ces chaînes générées. Les contraintes sont également un peu différentes: il essaie toujours d'ajouter le moins de caractères à chaque fois, mais les liens sont rompus en privilégiant d'abord les grilles carrées, puis les petites grilles, et enfin en ajoutant le mot le plus long.Le comportement qu'il affiche est d'alterner entre des périodes de remplissage d'espace et d'expansion rapide de la grille (malheureusement, il manquait de mots juste après une phase d'expansion rapide, il y a donc beaucoup d'espace vide autour des bords). Je soupçonne qu'avec quelques ajustements de la fonction de coût, il pourrait être fait pour obtenir un remplissage de l'espace supérieur à 50%.
Il y a 2 exécutables ici (pour éviter d'avoir à relancer tout le processus lors de l'amélioration itérative de l'algorithme). La sortie de l'un peut être canalisée directement dans l'autre:
Et enfin, le résultat:
Résultat alternatif (après avoir corrigé quelques bogues dans le programme qui biaisaient certaines directions et ajustaient la fonction de coût, j'ai obtenu une solution plus compacte mais moins optimale): 29275 caractères, 198x195 (75,8% remplis):
Encore une fois, je n'ai pas fait grand-chose pour optimiser ces programmes, donc cela prend du temps. Mais vous pouvez le regarder remplir la grille, ce qui est assez hypnotique.
la source
C ++, 34191 caractère "grille" (avec une intervention humaine minimale, 6 ou 7 peuvent facilement être enregistrés)
Cela devrait être considéré comme une limite pour le cas 2D, car la réponse est toujours une chaîne 1D. C'est juste mon code du défi précédent, mais avec la nouvelle possibilité d'inverser n'importe quelle chaîne. Cela nous donne beaucoup plus de possibilités pour combiner des mots (en particulier parce qu'il limite le pire des cas de supercordes sans chevauchement à 26; un pour chaque lettre de l'alphabet).
Pour un léger attrait visuel 2D, il met des sauts de ligne dans le résultat s'il peut le faire gratuitement (c'est-à-dire entre des mots se chevauchant 0).
Assez lent (toujours pas de mise en cache). Voici le code:
Résultat: http://pastebin.com/UTe2WMcz (4081 caractères de moins que le défi précédent)
Il est assez clair que des économies triviales peuvent être réalisées en plaçant les lignes
xd
etwv
verticales, coupant la ligne monstre. Puishhidetautisbneudui
peut se croiser avecd
, etlxwwwowaxocnnaesdda
avecw
. Cela enregistre 4 caractères.nbcllilhn
peut être substitué à uns
chevauchement existant (s'il en existe un) pour en enregistrer 2 de plus (ou juste 1 si aucun chevauchement n'existe et qu'il doit être ajouté verticalement à la place). Enfin, ilmjjrajaytq
peut être ajouté verticalement quelque part pour enregistrer 1. Cela signifie qu'avec une intervention humaine minimale, 6 à 7 caractères peuvent être enregistrés à partir du résultat.Je voudrais mettre cela en 2D avec la méthode suivante, mais j'ai du mal à trouver un moyen de l'implémenter sans faire l'algorithme O (n ^ 4), ce qui est assez peu pratique à calculer!
la source
PHP
celui-ci fait le travail de façon thématique; mais 10000 sont probablement trop de mots pour la récursivité. Le script est en cours d'exécution maintenant. (toujours exécuté 24 heures plus tard)
fonctionne très bien sur les petits répertoires, mais je peux faire une version itérative la semaine prochaine.
$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:
openCe n'est pas non plus très rapide; ne supprime que les sous-chaînes et trie les restes par longueur,
le reste est par force brute: essayez d'adapter les mots dans un rectangle, essayez sur un rectangle plus grand s'il échoue.
btw: La partie sous-chaîne a besoin de 4,5 minutes sur ma machine pour le grand répertoire
et le réduit à 6 190 mots; le tri sur eux prend 11 secondes.
la source