Encontre a fechadura mais combinada

18

Eu tenho um cadeado de combinação que tem letras em vez de números. É assim: http://pictures.picpedia.com/2012/09/Word_Combination_Padlock.jpg Existem 5 cilindros, cada um com 10 letras diferentes.

A maioria das pessoas gosta de usar uma palavra para sua combinação, em vez de uma sequência arbitrária de letras. (Menos seguro, é claro, mas mais fácil de lembrar.) Portanto, ao fabricar a fechadura, seria bom construí-la para ter uma combinação de letras que possam ser usadas para criar o máximo possível de palavras em inglês de 5 letras.

Sua tarefa, se você optar por aceitá-la, é encontrar uma atribuição de letras para as bobinas que permita criar o maior número possível de palavras. Por exemplo, sua solução pode ser

ABCDEFGHIJ DEFGHIJKLM ZYXWVUTSR ABCDEFGHIJ ABCDEFGHIJ

(Se você não estava se sentindo muito imaginativo).

Para obter consistência, use a lista de palavras em http://www.cs.duke.edu/~ola/ap/linuxwords

Qualquer palavra de 5 letras nessa lista está OK, incluindo nomes próprios. Ignore Sino e L'vov e qualquer outra palavra na lista que contenha um caracter não az.

O programa vencedor é aquele que produz o maior conjunto de palavras. No caso de vários programas encontrarem o mesmo resultado, o primeiro a ser publicado vence. O programa deve ser executado em menos de 5 minutos.

Edit: desde que a atividade acabou, e nenhuma solução melhor saiu, declaro Peter Taylor o vencedor! Obrigado a todos por suas soluções criativas.

Edwin Young
fonte
Como se pode contar nomes próprios, considerando que eles variam muito entre as culturas?
elssar
@elssar, Se bem entendi, qualquer palavra da lista é OK, independentemente de ser um nome adequado (em qualquer cultura).
Ugoren
Ah, certo, o que estava lá dentro não viu isso
elssar
Portanto, não é uma questão de código; mas lógica?
Brigand
2
Isso é marcado como desafio de código : qual é o desafio? Tudo o que você pediu é o valor que maximiza uma função cujo tamanho do domínio é de cerca de 110,3 bits. Portanto, não é possível forçar o problema com força bruta, mas deve ser possível obter a resposta exata e talvez até provar que está correto. Tendo tudo isso em mente, quais são os pré-requisitos para uma resposta a ser considerada e quais critérios você usará para selecionar um vencedor?
Peter Taylor

Respostas:

6

1275 palavras simples simples ganancioso

O código é c #. A solução produzida é

Score 1275 from ^[bcdfgmpstw][aehiloprtu][aeilnorstu][acdeklnrst][adehklrsty]$

Estou usando esse formato de saída porque é realmente fácil de testar:

grep -iE "^[bcdfgmpstw][aehiloprtu][aeilnorstu][acdeklnrst][adehklrsty]$" linuxwords.txt | wc

namespace Sandbox {
    class Launcher {
        public static void Main(string[] args)
        {
            string[] lines = _Read5s();
            int[][] asMasks = lines.Select(line => line.ToCharArray().Select(ch => 1 << (ch - 'a')).ToArray()).ToArray();
            Console.WriteLine(string.Format("{0} words found", lines.Length));

            // Don't even bother starting with a good mapping.
            int[] combos = _AllCombinations().ToArray();
            int[] best = new int[]{0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff};
            int bestSc = 0;
            while (true)
            {
                Console.WriteLine(string.Format("Score {0} from {1}", bestSc, _DialsToString(best)));

                int[] prevBest = best;
                int prevBestSc = bestSc;

                // Greedy hill-climbing approach
                for (int off = 0; off < 5; off++)
                {
                    int[] dials = (int[])prevBest.Clone();

                    dials[off] = (1 << 26) - 1;
                    int[][] filtered = asMasks.Where(mask => _Permitted(dials, mask)).ToArray();
                    int sc;
                    dials[off] = _TopTen(filtered, off, out sc);
                    if (sc > bestSc)
                    {
                        best = (int[])dials.Clone();
                        bestSc = sc;
                    }
                }

                if (bestSc == prevBestSc) break;
            }

            Console.WriteLine("Done");
            Console.ReadKey();
        }

        private static int _TopTen(int[][] masks, int off, out int sc)
        {
            IDictionary<int, int> scores = new Dictionary<int, int>();
            for (int k = 0; k < 26; k++) scores[1 << k] = 0;

            foreach (int[] mask in masks) scores[mask[off]]++;

            int rv = 0;
            sc = 0;
            foreach (KeyValuePair<int, int> kvp in scores.OrderByDescending(kvp => kvp.Value).Take(10))
            {
                rv |= kvp.Key;
                sc += kvp.Value;
            }
            return rv;
        }

        private static string _DialsToString(int[] dials)
        {
            StringBuilder sb = new StringBuilder("^");
            foreach (int dial in dials)
            {
                sb.Append('[');
                for (int i = 0; i < 26; i++)
                {
                    if ((dial & (1 << i)) != 0) sb.Append((char)('a' + i));
                }
                sb.Append(']');
            }
            sb.Append('$');
            return sb.ToString();
        }

        private static IEnumerable<int> _AllCombinations()
        {
            // \binom{26}{10}
            int set = (1 << 10) - 1;
            int limit = (1 << 26);
            while (set < limit)
            {
                yield return set;

                // Gosper's hack:
                int c = set & -set;
                int r = set + c;
                set = (((r ^ set) >> 2) / c) | r;
            }
        }

        private static bool _Permitted(int[] dials, int[] mask)
        {
            for (int i = 0; i < dials.Length; i++)
            {
                if ((dials[i] & mask[i]) == 0) return false;
            }
            return true;
        }

        private static string[] _Read5s()
        {
            System.Text.RegularExpressions.Regex word5 = new System.Text.RegularExpressions.Regex("^[a-z][a-z][a-z][a-z][a-z]$", System.Text.RegularExpressions.RegexOptions.Compiled);
            return File.ReadAllLines(@"d:\tmp\linuxwords.txt").Select(line => line.ToLowerInvariant()).Where(line => word5.IsMatch(line)).ToArray();
        }
    }
}
Peter Taylor
fonte
Eu estava prestes a editar minha resposta com esta solução exata, mas você me venceu.
cardboard_box
Quando eu executo a mesma pesquisa em subidas a partir de 1000 combinações aleatórias de partida e seleciono o melhor dos 1000 ótimos locais encontrados, ele parece sempre produzir a mesma solução, por isso parece ser o ideal global.
Peter Taylor
Isso depende da sua definição de provável ;-) Mas é ainda "confirmado" por outras abordagens que produzem 1275 no máximo. (E onde fez o movimento Quantum-Tic-Tac-Toe?)
Howard
@ Howard, isso era apenas um artefato do .Net que não suporta vários pontos de entrada em um único projeto. Eu tenho um projeto "sandbox" que eu uso para coisas como essa e geralmente altero o Mainmétodo para chamar _Mainmétodos diferentes .
Peter Taylor
Tentei um algoritmo genético e obtive o mesmo resultado em alguns minutos e depois nada na próxima hora, para não me surpreender se for o ideal.
cardboard_box
4

Python (3), 1273 ≈ 30,5%

Essa é uma abordagem realmente ingênua: mantenha um registro da frequência de cada letra em cada posição e elimine a "pior" letra até que as letras restantes caibam nos rolos. Estou surpreso que pareça se sair tão bem.

O mais interessante é que tenho quase exatamente a mesma saída que a solução C # 1275, exceto que tenho um Nno meu último rolo em vez de A. Essa Afoi a minha décima primeira eliminação também, mesmo antes de jogar fora a Ve a G.

from collections import Counter

def main(fn, num_reels, letters_per_reel):
    # Read ye words
    words = []
    with open(fn) as f:
        for line in f:
            word = line.strip().upper()
            if len(word) == num_reels and word.isalpha():
                words.append(word)

    word_pool_size = len(words)

    # Populate a structure of freq[reel_number][letter] -> count
    freq = [Counter() for _ in range(num_reels)]
    for word in words:
        for r, letter in enumerate(word):
            freq[r][letter] += 1

    while True:
        worst_reelidx = None
        worst_letter = None
        worst_count = len(words)
        for r, reel in enumerate(freq):
            # Skip reels that already have too-few letters left
            if len(reel) <= letters_per_reel:
                continue

            for letter, count in reel.items():
                if count < worst_count:
                    worst_reelidx = r
                    worst_letter = letter
                    worst_count = count

        if worst_letter is None:
            # All the reels are done
            break

        # Discard any words containing this worst letter, and update counters
        # accordingly
        filtered_words = []
        for word in words:
            if word[worst_reelidx] == worst_letter:
                for r, letter in enumerate(word):
                    freq[r][letter] -= 1
                    if freq[r][letter] == 0:
                        del freq[r][letter]
            else:
                filtered_words.append(word)
        words = filtered_words

    for reel in freq:
        print(''.join(sorted(reel)))

    print("{} words found (~{:.1f}%)".format(
        len(words), len(words) / word_pool_size * 100))

Produz:

BCDFGMPSTW
AEHILOPRTU
AEILNORSTU
ACDEKLNRST
DEHKLNRSTY
1273 words found (~30.5%)
Eevee
fonte
O que a porcentagem representa?
Joe Z.
porcentagem das palavras dadas que pode ser feita com o conjunto proposto de bobinas
Eevee
OK. (Uau, eu acabei de ver quem você era.) #
933 Joe Z.
ha, mundo pequeno.
Eevee
3

Mathematica , 1275 palavras repetidas vezes ...

Este código não é golfado, pois a pergunta não parece exigir isso.

wordlist = Flatten @ Import @ "http://www.cs.duke.edu/~ola/ap/linuxwords";
shortlist = Select[ToLowerCase@wordlist, StringMatchQ[#, Repeated[LetterCharacter, {5}]] &];
string = "" <> Riffle[shortlist, ","];

set = "a" ~CharacterRange~ "z";
gb = RandomChoice[set, {5, 10}];

best = 0;
While[True,
  pos = Sequence @@ RandomInteger /@ {{1, 5}, {1, 10}};
  old = gb[[pos]];
  gb[[pos]] = RandomChoice @ set;
  If[best < #,
    best = #; Print[#, "   ", StringJoin /@ gb],
    gb[[pos]] = old
  ] & @ StringCount[string, StringExpression @@ Alternatives @@@ gb]
]

A contagem de palavras rapidamente (menos de 10 segundos) evolui para 1275 na maioria das execuções, mas nunca ultrapassa isso. Tentei perturbar as letras mais de uma por vez, na tentativa de sair do máximo local teórico, mas isso nunca ajudou. Eu suspeito fortemente que 1275 é o limite para a lista de palavras fornecida. Aqui está uma corrida completa:

36   {tphcehmqkt,agvkqxtnpy,nkehuaakri,nsibxpctio,iafwdyhone}

37   {tpicehmqkt,agvkqxtnpy,nkehuaakri,nsibxpctio,iafwdyhone}

40   {tpicehmqkt,agvkqxtnpy,nkehuaakri,nsibxpctio,iafldyhone}

42   {tpicehmqkt,agvkqxtnpy,nkehuaakri,nsfbxpctio,iafldyhone}

45   {tpicehmrkt,agvkqxtnpy,nkehuaakri,nsfbxpctio,iafldyhone}

48   {tpicehmrkt,agvkwxtnpy,nkehuaakri,nsfbxpctio,iafldyhone}

79   {tpicehmskt,agvkwxtnpy,nkehuaakri,nsfbxpctio,iafldyhone}

86   {tpicehmskt,agvkwxtnpy,nkehuaakri,esfbxpctio,iafldyhone}

96   {tpicehmskt,agvkwxtnpy,nkehuaokri,esfbxpctio,iafldyhone}

97   {tpicehmskt,agvkwxtnpy,nkehuaokri,esfbxpctio,ipfldyhone}

98   {tpicehmskv,agvkwxtnpy,nkehuaokri,esfbxpctio,ipfldyhone}

99   {tpicehmskv,agvkwxtnpy,nkehuaokri,esfbzpctio,ipfldyhone}

101   {tpicehmskv,agvkwxtnpy,nkehuaokri,esfhzpctio,ipfldyhone}

102   {tpicehmskv,agvkwxtnpy,nkehuaokri,esfhzpctno,ipfldyhone}

105   {tpicehmskv,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldyhone}

107   {tpicehmskn,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldyhone}

109   {tpgcehmskn,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldyhone}

115   {tpgcehmsan,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldyhone}

130   {tpgcehmsan,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldyhons}

138   {tpgcehmsan,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldytons}

143   {tpgcehmsab,agvkwxtnpy,nkehuaokri,esfhzmctno,ipfldytons}

163   {tpgcehmsab,auvkwxtnpy,nkehuaokri,esfhzmctno,ipfldytons}

169   {tpgcehmsab,auvkwctnpy,nkehuaokri,esfhzmctno,ipfldytons}

176   {tpgcehmsab,auvkwctnpy,nkehuaokri,esfhzmctno,ihfldytons}

189   {tpgcehmsab,auvkwchnpy,nkehuaokri,esfhzmctno,ihfldytons}

216   {tpgcehmsab,auvkwchnpy,nkehtaokri,esfhzmctno,ihfldytons}

220   {tpgcehmsab,auvkwthnpy,nkehtaokri,esfhzmctno,ihfldytons}

223   {tpgcehmsab,auvkwthnpy,nkehtaokri,esfhbmctno,ihfldytons}

234   {tpgcehmsab,auvkwthnpy,nkegtaokri,esfhbmctno,ihfldytons}

283   {tpgcehmsab,auvkwthnpy,nkegtaokri,esfhbrctno,ihfldytons}

285   {tpdcehmsab,auvkwthnpy,nkegtaokri,esfhbrctno,ihfldytons}

313   {tpdcehmsab,auvkwthnly,nkegtaokri,esfhbrctno,ihfldytons}

371   {tpdcehmsab,auvkethnly,nkegtaokri,esfhbrctno,ihfldytons}

446   {tpdcehmsab,auvoethnly,nkegtaokri,esfhbrctno,ihfldytons}

451   {tpdcehmslb,auvoethnly,nkegtaokri,esfhbrctno,ihfldytons}

465   {tpdcwhmslb,auvoethnly,nkegtaokri,esfhbrctno,ihfldytons}

545   {tpdcwhmslb,auioethnly,nkegtaokri,esfhbrctno,ihfldytons}

565   {tpdcwhmslb,auioethnly,nkegtaocri,esfhbrctno,ihfldytons}

571   {tpdcwhmslb,auioethnly,nkegtaocri,esfhwrctno,ihfldytons}

654   {tpdcwhmslb,auioethnly,nkegtaocri,esfhwrctno,ihfedytons}

671   {tpdcwhmslb,auioethnly,nkegtaocri,esfhirctno,ihfedytons}

731   {tpdcwhmslb,auioethnly,nkegtaocri,esfhirctno,ihredytons}

746   {tpdcwhmslb,arioethnly,nkegtaocri,esfhirctno,ihredytons}

755   {tpdcwhmslb,arioethnuy,nkegtaocri,esfhirctno,ihredytons}

772   {tpdcwhmslb,arioethnuy,nkegtaocri,ekfhirctno,ihredytons}

786   {tpdcwhmslb,arioethnuy,nkegtaocri,ekfhirctno,lhredytons}

796   {tpdcwhmslb,arioethnuy,nkegtaocri,ekfhgrctno,lhredytons}

804   {tpdcwhmslb,arioethwuy,nkegtaocri,ekfhgrctno,lhredytons}

817   {tpdcwhmslb,arioethwuy,nklgtaocri,ekfhgrctno,lhredytons}

834   {tpdcwhmslb,arioethwuy,nklgtaocri,ekfhdrctno,lhredytons}

844   {tpdcwhmslb,arioethwup,nklgtaocri,ekfhdrctno,lhredytons}

887   {tpdcwhmslb,arioethwup,nklgtaocri,ekshdrctno,lhredytons}

901   {tpdcwhmslb,arioethwup,nklgtaouri,ekshdrctno,lhredytons}

966   {tpdcwhmslb,arioethwup,nklgtaouri,elshdrctno,lhredytons}

986   {tpdcwhmsfb,arioethwup,nklgtaouri,elshdrctno,lhredytons}

1015   {tpdcwhmsfb,arioethwup,nklgtaouri,elsidrctno,lhredytons}

1039   {tpdcwhmsfb,arioethwup,nklgtaouri,elsidrctno,khredytons}

1051   {tpdcwhmsfb,arioethwup,nklgtaouri,elskdrctno,khredytons}

1055   {tpdcwhmsfb,arioethwup,nklgtaouri,elskdrctno,khredytlns}

1115   {tpdcwhmsfb,arioethwup,nelgtaouri,elskdrctno,khredytlns}

1131   {tpdcwhmsfb,arioethwup,nelwtaouri,elskdrctno,khredytlns}

1149   {tpdcwhmsfb,arioethwup,nelwtaouri,elskdrctna,khredytlns}

1212   {tpdcwhmsfb,arioelhwup,nelwtaouri,elskdrctna,khredytlns}

1249   {tpdcwhmsfb,arioelhwup,nelstaouri,elskdrctna,khredytlns}

1251   {tpgcwhmsfb,arioelhwup,nelstaouri,elskdrctna,khredytlns}

1255   {tpgcwdmsfb,arioelhwup,nelstaouri,elskdrctna,khredytlns}

1258   {tpgcwdmsfb,arioelhwup,nelstaouri,elskdrctna,khredytlas}

1262   {tpgcwdmsfb,arioelhwut,nelstaouri,elskdrctna,khredytlas}

1275   {tpgcwdmsfb,arioelhput,nelstaouri,elskdrctna,khredytlas}

Aqui estão algumas outras seleções "vencedoras":

{"cbpmsftgwd", "hriuoepatl", "euosrtanli", "clknsaredt", "yhlkdstare"}
{"wptdsgcbmf", "ohlutraeip", "erotauinls", "lknectdasr", "sytrhklaed"}
{"cftsbwgmpd", "ropilhtaue", "niauseltor", "clstnkdrea", "esdrakthly"}
{"smgbwtdcfp", "ihulpreota", "ianrsouetl", "ekndasctlr", "kehardytls"}

Como Peter comenta, essas são realmente a mesma solução em diferentes ordens. Ordenado:

{"bcdfgmpstw", "aehiloprtu", "aeilnorstu", "acdeklnrst", "adehklrsty"}
Mr.Wizard
fonte
@belisarius Obrigado! É mais interessante com o ENABLE2k .
precisa saber é o seguinte
Eu estive considerando o NetworkFlow da Combinatorica para este, mas não encontrei uma maneira útil de usá-lo
Dr. belisarius
@belisarius Espero que você encontre um caminho; Eu gostaria de ver isso.
precisa saber é o seguinte
@belisarius pela maneira como meu código shortlistparece longo, e embora este não seja o Golf, eu gostaria de algo mais curto. Você pode ajudar?
precisa saber é o seguinte
1
Eu acho que suas seleções "vencedoras" são todas da mesma permutação de módulo nos mostradores.
Peter Taylor
2

Python, 1210 palavras (~ 29%)

Supondo que contei as palavras corretamente desta vez, isso é um pouco melhor que a solução de FakeRainBrigand. A única diferença é que eu adiciono cada rolo na ordem e removo todas as palavras da lista que não correspondem ao rolo, para obter uma distribuição um pouco melhor para os próximos rolos. Por esse motivo, fornece exatamente o mesmo primeiro rolo.

word_list = [line.upper()[:-1] for line in open('linuxwords.txt','r').readlines() if len(line) == 6]
cur_list = word_list
s = ['']*5
for i in range(5):
    count = [0]*26
    for j in range(26):
        c = chr(j+ord('A'))
        count[j] = len([x for x in cur_list if x[i] == c])
    s[i] = [chr(x+ord('A')) for x in sorted(range(26),lambda a,b: count[b] - count[a])[:10]]
    cur_list = filter(lambda x:x[i] in s[i],cur_list)
for e in s:
    print ''.join(e)
print len(cur_list)

O programa gera

SBCAPFDTMG
AOREILUHTP
ARIOLENUTS
ENTLRCSAID
SEYDTKHRNL
1210
caixa de papelão
fonte
Bom, e 1210 funciona no meu verificador.
Brigand
1

iPython ( 273 210 bytes, 1115 palavras)

1115/4176 * ~ 27%

Eu calculei isso no iPython, mas meu histórico (aparado para remover a depuração) ficou assim.

with open("linuxwords") as fin: d = fin.readlines()
x = [w.lower().strip() for w in d if len(w) == 6]
# Saving for later use:
# with open("5letter", "w") as fout: fout.write("\n".join(x))
from string import lowercase as low
low=lowercase + "'"
c = [{a:0 for a in low} for q in range(5)]
for w in x:
    for i, ch in enumerate(w):
        c[i][ch] += 1

[''.join(sorted(q, key=q.get, reverse=True)[:10]) for q in c]

Se estamos indo para breve; Eu poderia aparar isso.

x = [w.lower().strip() for w in open("l") if len(w)==6]
c=[{a:0 for a in"abcdefghijklmnopqrstuvwxyz'-"}for q in range(5)]
for w in[w.lower().strip()for w in open("l") if len(w)==6]:
 for i in range(5):c[i][w[i]]+=1
[''.join(sorted(q,key=q.get,reverse=True)[:10])for q in c]

Encurtado:

c=[{a:0 for a in"abcdefghijklmnopqrstuvwxyz'-"}for q in range(5)]
for w in[w.lower() for w in open("l")if len(w)==6]:
 for i in range(5):c[i][w[i]]+=1
[''.join(sorted(q,key=q.get,reverse=True)[:10])for q in c]

Meus resultados foram: ['sbcapfdtmg', 'aoeirulhnt', 'aironeluts', 'etnlriaosc', 'seyrdtnlah'].

* Minha matemática no 4176 pode ser um pouco curta devido a palavras com hífens ou apóstrofos sendo omitidos

Brigand
fonte
1
Embora essa solução seja uma boa heurística e provavelmente retorne uma boa solução, não acredito que seja garantida a devolução da solução ideal. O motivo é que você não está capturando as restrições entre os rolos: você está tratando cada rolo como uma variável independente, quando na verdade eles são dependentes. Por exemplo, pode ser que as palavras que compartilham a primeira letra mais comum tenham uma grande variação na distribuição de sua segunda letra. Se for esse o caso, sua solução pode produzir combinações de bobinas que, de fato, não permitem nenhuma palavra.
ESultanik
1

Q

? (todo) words

As palavras devem ser armazenadas em um arquivo chamado words

(!:')10#/:(desc')(#:'')(=:')(+:)w@(&:)(5=(#:')w)&(&/')(w:(_:)(0:)`:words)in\:.Q.a

Funciona em cerca de 170 ms no meu i7. Ele analisa a lista de palavras, procurando a letra mais comum em cada posição (obviamente filtrando os não candidatos). É uma solução ingênua e preguiçosa, mas produz um resultado razoavelmente bom com código mínimo.

Resultados:

"sbcapfdtmg"
"aoeirulhnt"
"aironeluts"
"etnlriaosc"
"seyrdtnlah"
skeevey
fonte
Quantas palavras com 5 letras você encontrou?
DavidC
Eu fiz a mesma coisa em python e tenho 16353.
cardboard_box
Esse é o mesmo algoritmo ganancioso do FakeRainBrigand?
Peter Taylor
1
@cardboard_box, seu resultado está definitivamente errado. Não existem muitas palavras de 5 letras no dicionário.
Peter Taylor
1
Sim, são 1115. Contei o número de letras corretas em qualquer palavra em vez do número de palavras corretas. Eu acho que preciso de outro café.
cardboard_box
0

Editar: Agora que as regras foram modificadas, essa abordagem é desqualificada. Vou deixar aqui, caso alguém esteja interessado, até que eu possa modificá-lo para as novas regras.

Python: 277 caracteres

Tenho certeza de que a versão generalizada desse problema é NP-Hard, e a pergunta não exigia encontrar a solução mais rápida , então aqui está um método de força bruta para fazer isso:

import itertools,string
w=[w.lower()[:-1] for w in open('w') if len(w)==6]
v=-1
for l in itertools.product(itertools.combinations(string.ascii_lowercase,10),repeat=5):
 c=sum(map(lambda d:sum(map(lambda i:i[0] in i[1],zip(d,l)))==5,w))
 if c>v:
  v=c
  print str(c)+" "+str(l)

Observe que renomeei o arquivo da lista de palavras para apenas "w" para salvar alguns caracteres.

A saída é o número de palavras possíveis de uma determinada configuração seguida pela própria configuração:

34 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
38 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'))
42 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'))
45 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'n'))
50 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'r'))
57 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 's'))
60 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'k', 's'))
64 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'l', 's'))
67 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'n', 's'))
72 (('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'r', 's'))
...

A última linha de saída antes do término do programa é garantida como a solução ideal.

ESultanik
fonte
Eu adoraria ver uma versão C ou ASM do seu código para que ele pudesse realmente terminar este ano :-) Ou pelo menos executá-lo até chegar ao 1116. Você poderia escrevê-lo sem o itool, para que eu possa executá-lo em jython ? (mais rápido do que python regular, mas mais fácil do que Cython.)
Brigand
Não importa com a coisa do jython. Eu precisava pegar o alfa. Ele ainda travou (muita memória), mas isso parece inevitável.
Brigand
Tenho certeza de que, mesmo que isso fosse implementado em montagem, levaria mais tempo do que minha vida para ser concluído no hardware atual :-P
ESultanik
O problema é que eu estou repetindo (26 escolha 10) ^ 5 ~ 4,23 * 10 ^ 33 possibilidades. Mesmo se pudéssemos testar uma possibilidade por nanossegundo, levaria cerca de 10 ^ 7 vezes a idade atual do universo para terminar.
ESultanik
1
Existem dois caracteres que não aparecem na 5ª posição em nenhuma palavra da lista de palavras fornecida, então você pode reduzir o número de possibilidades em um fator de cerca de 4. Foi assim que obtive "cerca de 110,3 bits" no meu comentário sobre a questão.
Peter Taylor