Scralphabet
Un sac normal de tuiles Scrabble contient les lettres suivantes ( ?
est une tuile vierge, qui peut représenter toute autre lettre):
AAAAAAAAABBCCDDDDEEEEEEEEEEEEFFGGGHHIIIIIIIIIJKLLLLMMNNNNNNOOOOOOOOPPQRRRRRRSSSSTTTTTTUUUUVVWWXYYZ??
Les lettres ont la valeur suivante:
{"A": 1,"B": 3,"C": 3,"D": 2,"E": 1,"F": 4,"G": 2,"H": 4,"I": 1,"J": 8,"K": 5,"L": 1,"M": 3,"N": 1,"O": 1,"P": 3,"Q": 10,"R": 1,"S": 1,"T": 1,"U": 1,"V": 4,"W": 4,"X": 8,"Y": 4,"Z": 10,"?": 0}
Étant donné un sac normal de tuiles de Scrabble, construisez l'ensemble de mots qui ne se croisent pas (c.-à-d., Des mots individuels, pas sur un tableau de Scrabble) dans les conditions suivantes:
- Le score de chaque mot est
sum(letter_values) * length(word)
. - Vous ne pouvez inclure qu'un maximum d'un mot commençant par chaque lettre de l'alphabet (donc un maximum de 26 mots).
- Seuls les mots Scrabble valides (de ce dictionnaire ) peuvent être inclus. Vous pouvez lire le dictionnaire à partir d'un fichier, le coder en dur (ugh) ou le gratter sur le site Web.
- Vous n'avez pas besoin d'utiliser toutes les tuiles, mais toutes les tuiles inutilisées forment un seul mot, marqué de la même manière, ce qui soustrait de votre score.
Si vous le souhaitez, votre code peut accepter deux entrées: le contenu du sac sous forme de chaîne et les valeurs des lettres dans un format similaire à un python dict
(comme ci-dessus); vous pouvez également coder en dur le contenu du sac et les valeurs des lettres. Il devrait afficher les mots de votre ensemble, leurs scores respectifs et votre score total, dans un format raisonnable.
Le jeu de mots ayant obtenu le score le plus élevé l'emporte, les liens allant au premier affiché.
la source
print"FOO18\nBAR15\nBAZ42\n...\n1523"
?Réponses:
C, 2765 (optimal)
Éditer
Maintenant le tout dans un seul fichier C. Cela trouve juste toutes les solutions optimales. Ils doivent tous avoir 6 mots de 15 lettres et un mot de 10 lettres composé de 8 lettres de valeur 1 et deux blancs. Pour cela, je n'ai besoin que de charger une fraction du dictionnaire et je n'ai pas besoin de chercher des mots de 15 lettres avec des blancs. Le code est une simple recherche approfondie approfondie en premier.
Usage:
Notez que chaque solution est imprimée deux fois car lors de l'ajout d'un mot «W» à 15 lettres, 2 commandes sont créées car il y a 2 tuiles «W».
La première solution trouvée avec la répartition des points:
Edit: explication
Qu'est-ce qui rend possible la recherche dans tout l'espace? Lors de l'ajout d'un nouveau mot, je ne prends en compte que les mots qui ont la lettre restante la plus rare. Cette lettre doit de toute façon être dans un mot (et un mot de 15 lettres car ce sera une lettre non 1 valeur, bien que je ne vérifie pas cela). Je commence donc par des mots contenant des mots
J, Q, W, W, X, Z
qui comptent50, 100, 100, 100, 200, 500
. Aux niveaux inférieurs, j'obtiens plus de coupure car certains mots sont éliminés par le manque de lettres. Étendue de l'arborescence de recherche à chaque niveau:Bien sûr, beaucoup de coupures sont obtenues en ne vérifiant pas les solutions non optimales (blancs en mots de 15 lettres ou mots plus courts). Il est donc heureux que la solution 2765 puisse être obtenue avec ce dictionnaire (mais c'était proche, seules 2 combinaisons de mots de 15 lettres donnent un reste raisonnable). D'un autre côté, il est facile de modifier le code pour trouver des combinaisons avec un score inférieur où les 10 lettres restantes ne sont pas toutes à 1, mais il serait plus difficile de prouver que ce serait une solution optimale.
Le code montre également un cas classique d'optimisation prématurée. Cette version de la
matches
fonction rend le code seulement 30% plus lent:J'ai même compris comment rendre la comparaison parallèle de bits magique encore plus courte que dans mon code d'origine (le quartet le plus élevé ne peut pas être utilisé dans ce cas, mais ce n'est pas un problème, car je n'ai besoin que de 26 sur 32 quartets):
Mais cela ne donne aucun avantage.
Éditer
En écrivant l'explication ci-dessus, j'ai réalisé que la plupart du temps est consacré à la recherche dans la liste de mots de ceux contenant une lettre spécifique qui n'est pas dans la
matches
fonction. Le calcul initial des listes a donné une accélération de 10 fois.la source
Python 2, score:
18402162Ce programme trouve d'abord le meilleur mot de score disponible avec les tuiles données (sans utiliser de caractères génériques), puis fait 10000 tentatives pour inclure des mots aléatoires qui répondent aux contraintes du premier caractère unique et ayant des tuiles disponibles. Avec les constantes actuelles, le programme prend 27 secondes pour s'exécuter sur ma machine. L'utilisation de constantes plus grandes trouverait probablement une combinaison de mots avec un score plus élevé.
MISE À JOUR: utilise désormais un algorithme de sélection en 2 étapes, de sorte qu'il trouve le meilleur des 50 mots à chaque étape de sélection. Le score de pénalité est désormais également utilisé dans l'algorithme d'évaluation.
J'inclus ici le meilleur de quelques runs:
Notez que je n'utilise pas les caractères génériques et paie une pénalité plus importante (en raison de la longueur des mots). Une amélioration future pourrait inclure l'utilisation de caractères génériques.
la source
Recuit simulé (score 2246)
Malheureusement, cela n'est pas déterministe. Je vais essayer de résoudre ce problème et de trouver une graine déterministe qui donne une meilleure valeur.
la source
Python, score
263826752676268926992717Résultat:
Code:
Explication:
Recherche en profondeur d'abord qui recherche dans tout l'arbre, en choisissant parmi les
picks
meilleurs mots à chaque étape.Je trie la liste de mots entière une fois par score au début. Après avoir sélectionné chaque mot, pour la prochaine itération, je filtre tous les mots qui ne sont plus possibles, préservant l'ordre, donc je n'ai pas à trier la liste à chaque étape. Pour gérer les caractères génériques, s'il y a une possibilité qu'un caractère générique soit nécessaire, je sélectionne les 10000 meilleurs candidats, remplace les lettres manquantes par des caractères génériques si nécessaire et retrie en fonction des nouveaux scores (inférieurs).
Cette sortie est destinée
picks=5
et a8m01s
fonctionné sur ma machine à 8 cœurs.la source
Java 8, score
26412681Le programme commence par prendre les 40 meilleurs mots. Pour chaque mot, il trouve les 40 meilleurs mots à suivre. Des 1600 combinaisons, le programme prend les 40 meilleures. Pour chaque combinaison, les 40 meilleurs mots sont trouvés et le cycle se répète.
Lorsqu'il ne reste que quelques tuiles, les lettres restantes sont combinées avec les deux blancs pour le mot final.
Mise à jour
J'ai augmenté le seuil aux 50 meilleurs mots. De plus, chaque combinaison n'ajoute que des mots inférieurs à ceux déjà présents. Cela empêche plusieurs permutations du même groupe.
Le programme:
la source
Perl, score: 2655
2630Utilisation:
L'utilisation de blancs ne donne en fait pas grand-chose tout en ralentissant considérablement l'exécution:
Après avoir ajouté quelques heuristiques:
la source
Python 3, score 2735
(Le score optimal de 2765, "6 mots de 15 lettres et un mot de 10 lettres composé de 8 lettres de valeur 1 et deux blancs" a été atteint par nutki .)
J'ai utilisé une approche gourmande similaire aux autres:
Je commence par des listes à un élément contenant les mots les mieux notés contenant des Q.
À chaque étape pour chaque élément de liste, je crée de
k = 800
nouvelles listes avec les meilleurs mots légaux pour la liste. À partir de la liste agrégée des listes, je conserve les listes lesk
plus performantes et répète le processus 10 fois.Notez que vous pouvez obtenir les
k
éléments supérieurs d'unen
liste de -long dans O (n + k * log n) qui est O (n) sik<<n
comme dans notre cas (k = 800, n ~= 250000
) avec une file d'attente de tas. Je suppose que cette méthode n'est pas utilisée dans d'autres soumissions, d'où lesk
valeurs plus petites .J'utilise des caractères génériques le long du chemin si nécessaire pour les mots.
Le temps d'exécution est de quelques minutes
k = 800
. Des valeurs plus élevées et d'autres optimisations n'ont pas encore donné de meilleurs résultats.Résultat:
J'ai expérimenté avec le produit Descartes des meilleurs mots contenant Q, J et X car ces lettres partagent à peine des mots. Mon meilleur score avec cette startegy était 2723 (
DEMISEMIQUAVERS OXYPHENBUTAZONE INTERSUBJECTIVE FLASHFORWARDING KNOWLEDGABILITY RADIOPROTECTION ANALOGUE EA
).Le code spaghetti compliqué inutile (avec des traces d'expérimentation avec d'autres méthodes):
la source