Encuentra el candado de combinación más elegante

18

Tengo un candado de combinación que tiene letras en lugar de números. Se ve así: http://pictures.picpedia.com/2012/09/Word_Combination_Padlock.jpg Hay 5 carretes, cada uno de los cuales tiene 10 letras diferentes.

A la mayoría de las personas les gusta usar una palabra para su combinación en lugar de una cadena arbitraria de letras. (Menos seguro, por supuesto, pero más fácil de recordar). Entonces, al fabricar el candado, sería bueno construirlo para tener una combinación de letras que se pueda usar para crear la mayor cantidad posible de palabras en inglés de 5 letras.

Su tarea, si elige aceptarla, es encontrar una asignación de letras a los carretes que permita crear tantas palabras como sea posible. Por ejemplo, su solución podría ser

ABCDEFGHIJ DEFGHIJKLM ZYXWVUTSR ABCDEFGHIJ ABCDEFGHIJ

(Si no te sientes demasiado imaginativo, eso es).

Para mayor coherencia, utilice la lista de palabras en http://www.cs.duke.edu/~ola/ap/linuxwords

Cualquier palabra de 5 letras en esa lista está bien, incluidos los nombres propios. Ignora Sino y L'vov y cualquier otra palabra en la lista que contenga un carácter no az.

El programa ganador es el que produce el mayor conjunto de palabras. En el caso de que varios programas encuentren el mismo resultado, gana el primero que se publique. El programa debería ejecutarse en menos de 5 minutos.

Editar: como la actividad ha disminuido y no han surgido mejores soluciones, ¡declaro a Peter Taylor el ganador! Gracias a todos por sus soluciones ingeniosas.

Edwin Young
fuente
¿Cómo se pueden contar los nombres propios teniendo en cuenta que varían tanto entre culturas?
elssar
@elssar, si entiendo correctamente, cualquier palabra en la lista está bien, independientemente de si es un nombre propio (en cualquier cultura).
Ugoren
Ah, claro, ahí dentro , no vi eso
elssar
Entonces, no es una pregunta de código; pero la logica?
Brigante el
2
Esto está etiquetado como código-desafío : ¿cuál es el desafío? Todo lo que ha pedido es el valor que maximiza una función cuyo tamaño de dominio es de aproximadamente 110.3 bits. Por lo tanto, no es factible forzar el problema por fuerza bruta, pero debería ser factible obtener la respuesta exacta y tal vez incluso demostrar que es correcto. Teniendo en cuenta todo eso, ¿cuáles son los requisitos previos para que se considere una respuesta y qué criterios utilizará para seleccionar un ganador?
Peter Taylor

Respuestas:

6

1275 palabras por simple escalada codiciosa

El código es C #. La solución producida es

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

Estoy usando ese formato de salida porque es realmente fácil de probar:

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
fuente
Estaba a punto de editar mi respuesta con esta solución exacta, pero me ganaste.
Cartón_box
Cuando ejecuto la misma búsqueda de escalada entre 1000 combinaciones iniciales al azar y selecciono la mejor de las 1000 óptimas locales encontradas, parece que siempre produce la misma solución, por lo que parece ser el óptimo global.
Peter Taylor
Eso depende de su definición de probable ;-) Pero está más "confirmado" por otros enfoques que producen 1275 como máximo. (¿Y adónde fue el Quantum-Tic-Tac-Toe?)
Howard
@Howard, eso fue solo un artefacto de .Net que no admite múltiples puntos de entrada en un solo proyecto. Tengo un proyecto "sandbox" que uso para cosas como esta, y generalmente cambio el Mainmétodo para llamar a diferentes _Mainmétodos.
Peter Taylor
Probé un algoritmo genético y obtuve el mismo resultado en unos minutos, y luego nada en la siguiente hora, por lo que no me sorprendería si es lo óptimo.
cardboard_box
4

Python (3), 1273 ≈ 30.5%

Este es un enfoque realmente ingenuo: mantenga una cuenta de la frecuencia de cada letra en cada posición, luego elimine la "peor" letra hasta que las letras restantes quepan en los carretes. Me sorprende que parezca hacerlo tan bien.

Lo más interesante es que tengo casi exactamente la misma salida que la solución C # 1275, excepto que tengo un Núltimo carrete en lugar de A. Esa Afue mi undécima y última eliminación, incluso antes de tirar a Vy 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))

Produce:

BCDFGMPSTW
AEHILOPRTU
AEILNORSTU
ACDEKLNRST
DEHKLNRSTY
1273 words found (~30.5%)
Eevee
fuente
¿Qué representa el porcentaje?
Joe Z.
porcentaje de las palabras dadas que se pueden hacer con el conjunto de carretes propuesto
Eevee
Bueno. (Whoa, acabo de ver quién eras.)
Joe Z.
ja, pequeño mundo.
Eevee
3

Mathematica , 1275 palabras una y otra vez ...

Este código no es Golfed ya que la pregunta no parece requerirlo.

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

El conteo de palabras rápidamente (menos de 10 segundos) evoluciona a 1275 en la mayoría de las carreras, pero nunca supera eso. Traté de perturbar las letras por más de una a la vez en un intento de salir de un máximo local teórico, pero nunca me ayudó. Sospecho firmemente que 1275 es el límite para la lista de palabras dada. Aquí hay una carrera 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}

Aquí hay algunas otras selecciones "ganadoras":

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

Como Peter comenta, en realidad son la misma solución en diferentes órdenes. Ordenados:

{"bcdfgmpstw", "aehiloprtu", "aeilnorstu", "acdeklnrst", "adehklrsty"}
Señor mago
fuente
@belisarius Gracias! Es más interesante con ENABLE2k .
Mr.Wizard
He estado considerando el NetworkFlow de Combinatorica para este, pero no he encontrado una forma útil de usarlo
Dr. belisarius
@belisarius Espero que encuentres un camino; Me gustaría ver eso.
Mr.Wizard
@belisarius, por cierto, mi código se shortlistsiente largo, y aunque esto no es Golf, me gustaría algo más corto. ¿Puede usted ayudar?
Mr.Wizard
1
Creo que sus selecciones "ganadoras" son todas la misma permutación de módulo dentro de los diales.
Peter Taylor el
2

Python, 1210 palabras (~ 29%)

Asumiendo que conté las palabras correctamente esta vez, esto es un poco mejor que la solución de FakeRainBrigand. La única diferencia es que agrego cada carrete en orden y luego elimino todas las palabras de la lista que no coinciden con el carrete para obtener una distribución ligeramente mejor para los próximos carretes. Debido a esto, da exactamente el mismo primer carrete.

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)

El programa sale

SBCAPFDTMG
AOREILUHTP
ARIOLENUTS
ENTLRCSAID
SEYDTKHRNL
1210
caja de cartón
fuente
Agradable, y 1210 funciona en mi corrector.
Brigante
1

iPython ( 273 210 Bytes, 1115 palabras)

1115/4176 * ~ 27%

Calculé esto en iPython, pero mi historial (recortado para eliminar la depuración) se veía así.

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]

Si vamos para abreviar; Podría recortarlo para esto.

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]

Acortado:

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]

Mis resultados fueron los siguientes: ['sbcapfdtmg', 'aoeirulhnt', 'aironeluts', 'etnlriaosc', 'seyrdtnlah'].

* Mis matemáticas en el 4176 pueden ser un poco cortas debido a las palabras con guiones o apóstrofes que se omiten

Bandido
fuente
1
Si bien esta solución es una buena heurística y probablemente devolverá una buena solución, no creo que se garantice que devuelva la solución óptima. La razón es que no está capturando las restricciones entre los carretes: está tratando cada carrete como una variable independiente cuando de hecho son dependientes. Por ejemplo, podría darse el caso de que las palabras que comparten la primera letra más común tengan una gran variación en la distribución de su segunda letra. Si tal es el caso, entonces su solución podría producir combinaciones de carretes que de hecho no permiten ninguna palabra.
ESultanik
1

Q

? (todo) palabras

Las palabras deben almacenarse en un archivo llamado words

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

Se ejecuta en aproximadamente 170 ms en mi i7. Analiza la lista de palabras, buscando la letra más común en cada posición (obviamente filtrando a los no candidatos). Es una solución ingenua perezosa, pero produce un resultado razonablemente bueno con un código mínimo.

Resultados:

"sbcapfdtmg"
"aoeirulhnt"
"aironeluts"
"etnlriaosc"
"seyrdtnlah"
skeevey
fuente
¿Cuántas palabras de 5 letras encontraste?
DavidC
Hice lo mismo en pitón y me 16353.
cardboard_box
¿Es este el mismo algoritmo codicioso que el de FakeRainBrigand?
Peter Taylor
1
@cardboard_box, tu resultado definitivamente es incorrecto. No hay tantas palabras de 5 letras en el diccionario.
Peter Taylor
1
Sí, es 1115. Conté el número de letras correctas en cualquier palabra en lugar del número de palabras correctas. Creo que necesito otro café.
cartón_en
0

Editar: ahora que las reglas se han modificado, este enfoque está descalificado. Lo dejaré aquí en caso de que alguien esté interesado hasta que eventualmente lo modifique para las nuevas reglas.

Python: 277 caracteres

Estoy bastante seguro de que la versión generalizada de este problema es NP-Hard, y la pregunta no requería encontrar la solución más rápida , así que aquí hay un método de fuerza bruta para hacerlo:

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)

Tenga en cuenta que cambié el nombre del archivo de lista de palabras a solo "w" para guardar algunos caracteres.

La salida es el número de palabras que son posibles de una configuración dada seguida de la configuración misma:

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

Se garantiza que la última línea de salida antes de que finalice el programa sea la solución óptima.

ESultanik
fuente
Me encantaría ver una versión C o ASM de su código para que realmente pueda terminar este año :-) O al menos ejecutarlo hasta llegar a 1116. ¿Podría escribirlo sin itertools, para que pueda ejecutarlo en jython ? (Más rápido que Python normal, pero más fácil que Cython.)
Brigante
No importa lo de jython. Necesitaba agarrar el alfa. Todavía se bloqueó (demasiada memoria) pero eso parece inevitable.
Brigante
Estoy bastante seguro de que incluso si esto se implementara en el ensamblaje, tomaría más tiempo que mi vida completarlo en el hardware actual
:-P
El problema es que estoy iterando sobre (26 elegir 10) ^ 5 ≈ 4.23 * 10 ^ 33 posibilidades. Incluso si pudiéramos probar una posibilidad por nanosegundo, tomaría aproximadamente 10 ^ 7 veces la edad actual del universo para terminar.
ESultanik
1
Hay dos caracteres que no aparecen en la quinta posición en ninguna palabra de la lista de palabras dada, por lo que puede reducir el número de posibilidades en un factor de aproximadamente 4. Así es como obtuve "aproximadamente 110.3 bits" en mi comentario sobre la pregunta.
Peter Taylor