Trova il lucchetto a combinazione più prolisso


18

Ho un lucchetto a combinazione che ha lettere anziché numeri. Sembra così: http://pictures.picpedia.com/2012/09/Word_Combination_Padlock.jpg Ci sono 5 rulli, ognuno dei quali ha 10 lettere diverse.

Alla maggior parte delle persone piace usare una parola per la loro combinazione piuttosto che una stringa di lettere arbitraria. (Meno sicuro, ovviamente, ma più facile da ricordare.) Quindi quando si produce il lucchetto, sarebbe bene costruirlo per avere una combinazione di lettere che può essere usata per creare quante più parole inglesi di 5 lettere possibile.

Il tuo compito, se scegli di accettarlo, è quello di trovare un'assegnazione di lettere ai rulli che consentirà di creare quante più parole possibile. Ad esempio, la tua soluzione potrebbe essere

ABCDEFGHIJ DEFGHIJKLM ZYXWVUTSR ABCDEFGHIJ ABCDEFGHIJ

(Se non ti sentivi troppo fantasioso, questo è).

Per coerenza, utilizzare l'elenco delle parole all'indirizzo http://www.cs.duke.edu/~ola/ap/linuxwords

Qualsiasi parola di 5 lettere in quell'elenco è OK, compresi i nomi propri. Ignora Sino- e L'vov e qualsiasi altra parola nell'elenco che contenga un carattere non az.

Il programma vincente è quello che produce il più grande insieme di parole. Nel caso in cui più programmi trovino lo stesso risultato, vince il primo ad essere pubblicato. Il programma dovrebbe funzionare in meno di 5 minuti.

Modifica: da quando l'attività è cessata e non sono state trovate soluzioni migliori, dichiaro Peter Taylor il vincitore! Grazie a tutti per le vostre soluzioni creative.


Come si possono contare i nomi propri considerando che variano così tanto da una cultura all'altra?
elssar,

@elssar, Se ho capito bene, qualsiasi parola nell'elenco è OK, indipendentemente dal fatto che sia un nome proprio (in qualsiasi cultura).
ugoren,

Oh giusto, l' lì dentro , non ha visto che
elssar

Quindi, non una domanda di codice; ma la logica?
Brigand,

2
Questo è etichettato come code-challenge : qual è la sfida? Tutto quello che hai chiesto è il valore che massimizza una funzione la cui dimensione del dominio è di circa 110,3 bit. Quindi non è possibile forzare bruscamente il problema, ma dovrebbe essere fattibile ottenere la risposta esatta e forse anche dimostrarlo correttamente. Tenendo presente tutto ciò, quali sono i prerequisiti per una risposta da considerare e quali criteri userete per selezionare un vincitore?
Peter Taylor,

Risposte:


6

1275 parole da una semplice avida arrampicata in collina

Il codice è C #. La soluzione prodotta è

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

Sto usando quel formato di output perché è davvero facile da testare:

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();
        }
    }
}

Stavo per modificare la mia risposta con questa soluzione esatta, ma mi hai battuto.
cardboard_box

Quando eseguo la stessa ricerca di arrampicata in collina da 1000 combinazioni casuali di partenza e seleziono il migliore dei 1000 optima locali trovati, sembra sempre produrre la stessa soluzione, quindi sembra essere l'ottimale globale.
Peter Taylor,

Dipende dalla tua definizione di probabile ;-) Ma è ulteriormente "confermato" da altri approcci che danno il massimo 1275. (E dove sono finiti i Quantum-Tic-Tac-Toe?)
Howard,

@Howard, quello era solo un artefatto di .Net che non supportava più punti di ingresso in un singolo progetto. Ho un progetto "sandbox" che uso per cose come questa e di solito cambio il Mainmetodo per chiamare _Mainmetodi diversi .
Peter Taylor,

Ho provato un algoritmo genetico e ho ottenuto lo stesso risultato in pochi minuti, e poi nulla nell'ora successiva, quindi non sarei sorpreso se fosse ottimale.
cardboard_box

4

Python (3), 1273 ≈ 30,5%

Questo è un approccio davvero ingenuo: tenere un conto della frequenza di ogni lettera in ogni posizione, quindi eliminare la lettera "peggiore" fino a quando le lettere rimanenti si adatteranno sui rulli. Sono sorpreso che sembra fare così bene.

La cosa più interessante è che ho quasi esattamente lo stesso output della soluzione C # 1275, tranne per il fatto che ne ho uno Nsull'ultima bobina anziché A. Anche questa è Astata la mia undicesima eliminazione, anche prima di buttare via ae Va 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))

produce:

BCDFGMPSTW
AEHILOPRTU
AEILNORSTU
ACDEKLNRST
DEHKLNRSTY
1273 words found (~30.5%)

Cosa rappresenta la percentuale?
Joe Z.

percentuale delle parole date che possono essere fatte con il set di bobine proposto
Eevee,

Va bene. (Whoa, ho appena visto chi eri.)
Joe Z.

ah, piccolo mondo.
Eevee,

3

Mathematica , 1275 parole ancora e ancora ...

Questo codice non è golfato in quanto la domanda non sembra richiederlo.

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]
]

Il conteggio delle parole rapidamente (meno di 10 secondi) si evolve a 1275 sulla maggior parte delle corse ma non va mai oltre. Ho provato a turbare le lettere di più di una alla volta nel tentativo di uscire da un massimo locale teorico, ma non mi è mai servito. Sospetto fortemente che 1275 sia il limite per l'elenco di parole indicato. Ecco una corsa 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}

Ecco alcune altre selezioni "vincenti":

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

Come commenta Peter, in realtà sono la stessa soluzione in diversi ordini. Smistato:

{"bcdfgmpstw", "aehiloprtu", "aeilnorstu", "acdeklnrst", "adehklrsty"}

@belisarius Grazie! È più interessante con ENABLE2k .
Mr.Wizard,

Ho considerato NetworkFlow di Combinatorica per questo, ma non ho trovato un modo utile per usarlo
Dr. belisarius

@belisarius Spero che tu trovi un modo; Mi piacerebbe vederlo
Mr.Wizard,

@belisarius dal modo in cui il mio codice shortlistsembra lungo, e anche se questo non è il golf, vorrei qualcosa di più corto. Puoi aiutare?
Mr.Wizard,

1
Penso che le tue selezioni "vincenti" abbiano tutte la stessa permutazione modulo all'interno dei quadranti.
Peter Taylor,

2

Python, 1210 parole (~ 29%)

Supponendo di aver contato correttamente le parole questa volta, è leggermente meglio della soluzione di FakeRainBrigand. L'unica differenza è che aggiungo ogni bobina in ordine, quindi rimuovo dall'elenco tutte le parole che non corrispondono alla bobina, in modo da ottenere una distribuzione leggermente migliore per le bobine successive. Per questo motivo, fornisce esattamente la stessa prima bobina.

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)

Il programma esce

SBCAPFDTMG
AOREILUHTP
ARIOLENUTS
ENTLRCSAID
SEYDTKHRNL
1210

Bello, e 1210 funziona nel mio correttore.
Brigand,

1

iPython ( 273 210 byte, 1115 parole)

1115/4176 * ~ 27%

Li ho calcolati in iPython, ma la mia storia (tagliata per rimuovere il debug) era simile a questa.

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 stiamo andando in breve; Potrei tagliarlo a questo.

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]

abbreviato:

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]

I miei risultati sono stati: ['sbcapfdtmg', 'aoeirulhnt', 'aironeluts', 'etnlriaosc', 'seyrdtnlah'].

* La mia matematica sul 4176 potrebbe essere un po 'breve a causa dell'omissione di parole con trattini o apostrofi


1
Sebbene questa soluzione sia una buona euristica e probabilmente restituirà una buona soluzione, non credo che sia garantita la restituzione della soluzione ottimale. Il motivo è che non stai catturando i vincoli tra le bobine: stai trattando ogni bobina come una variabile indipendente quando in realtà sono dipendenti. Ad esempio, potrebbe accadere che le parole che condividono la prima lettera più comune abbiano una grande varianza nella distribuzione della loro seconda lettera. In tal caso, la tua soluzione potrebbe produrre combinazioni di bobine che in realtà non consentono alcuna parola.
ESultanik,

1

Q

? (todo) parole

Le parole dovrebbero essere memorizzate in un file chiamato words

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

Funziona in circa 170 ms sul mio i7. Analizza l'elenco di parole, cercando la lettera più comune in ogni posizione (ovviamente filtrando tutti i non candidati). È una soluzione ingenua pigra ma produce un risultato ragionevolmente buono con un codice minimo.

risultati:

"sbcapfdtmg"
"aoeirulhnt"
"aironeluts"
"etnlriaosc"
"seyrdtnlah"

Quante parole di 5 lettere hai trovato?
DavidC,

Ho fatto la stessa cosa in Python e ottenuto 16353.
cardboard_box

È lo stesso avido algoritmo di FakeRainBrigand?
Peter Taylor,

1
@cardboard_box, il tuo risultato è decisamente sbagliato. Non ci sono molte parole di 5 lettere nel dizionario.
Peter Taylor,

1
Sì, è 1115. Ho contato il numero di lettere corrette in qualsiasi parola anziché il numero di parole corrette. Penso di aver bisogno di un altro caffè.
cardboard_box

0

Modifica: ora che le regole sono state modificate, questo approccio è squalificato. Lo lascerò qui nel caso qualcuno fosse interessato fino a quando non riesco a modificarlo per le nuove regole.

Python: 277 personaggi

Sono abbastanza sicuro che la versione generalizzata di questo problema sia NP-Hard, e la domanda non richiedesse di trovare la soluzione più veloce , quindi ecco un metodo a forza bruta per farlo:

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)

Si noti che ho rinominato il file dell'elenco di parole in "w" per salvare alcuni caratteri.

L'output è il numero di parole possibili da una determinata configurazione seguito dalla configurazione stessa:

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'))
...

L'ultima riga di output prima della fine del programma è garantita per essere la soluzione ottimale.


Mi piacerebbe vedere una versione C o ASM del tuo codice in modo che possa effettivamente finire quest'anno :-) O almeno eseguirlo fino a quando non arriva a 1116. Potresti scriverlo senza itertools, quindi posso eseguirlo su jython ? (più veloce del normale pitone, ma più facile del cython.)
Brigand,

Non importa nulla della cosa jython. Avevo bisogno di afferrare l'alfa. Si è comunque bloccato (troppa memoria) ma ciò sembra inevitabile.
Brigand,

Sono abbastanza sicuro che anche se questo fosse implementato in assembly, il completamento dell'hardware corrente richiederebbe più tempo della mia vita :-P
ESultanik,

Il problema è che sto ripetendo (26 scegli 10) ^ 5 ≈ 4.23 * 10 ^ 33 possibilità. Anche se potessimo testare una possibilità per nanosecondo, occorrerebbero circa 10 ^ 7 volte l'attuale età dell'universo per finire.
ESultanik,

1
Esistono due caratteri che non compaiono in quinta posizione in nessuna parola nell'elenco di parole dato, quindi puoi ridurre il numero di possibilità di un fattore di circa 4. Ecco come ho ottenuto "circa 110,3 bit" nel mio commento su la domanda.
Peter Taylor,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.