2009-04-15 22 views
5

Hola me encontré con este rompecabezas que es un subconjunto del famoso tipo de palabra y rompecabezas basados ​​en números llamados Cryptarithms. Supongamos que tiene una expresión comoManera eficiente de resolver Cryptarithms

S E N D + M O R E = M O N E Y

Ahora la parte interesante hay que, cada alfabeto está representando un dígito único partir de la 0-9. Quería escribir un solucionador generalizado, pero terminé escribiendo una solución bruta forzada para ello. Cualquier tomador como puedo resolverlo?

Creo que se puede resolver usando lógica de predicados o teoría de conjuntos. Y estoy particularmente interesado en encontrar soluciones basadas en C# o Python. Cualquiera.?

Respuesta

7

En PyCon de este año, Raymond Hettinger habló sobre la programación de AI en Python, y ha cubierto Cryptarithms.

El video de la charla completa se puede ver here, y el libro de cocina con la solución se puede encontrar en this link.

+0

+1: una de las mejores charlas de PyCon IMHO de este año – miles82

+0

gracias. ¡Seguro que fue un enlace increíble! –

+0

Toda esa charla fue buena. El solucionador de jarras de galones '(3, 5, 8)' me recordó a Die Hard 3. – Droogans

0

this puede ser de alguna ayuda

Editar: la respuesta en el enlace wiki informados también es útil!

2

Este es un problema tan pequeño que una solución de fuerza bruta no es un mal método. Suponiendo que cada letra debe representar un dígito único (es decir, no permitiremos la solución S = 9, M = 1, * = 0), vemos que el número de combinaciones para intentar es n!, donde n es el número de letras únicas en el cryptarithm. El número máximo teórico de combinaciones para evaluar es 10! = 3 628 800, que es un número muy pequeño para una computadora.

Si permitimos varias letras para representar el mismo número, el número de combinaciones para intentar estará delimitada por n 10 ^, de nuevo, donde n es el número de letras únicas. Suponiendo solo letras mayúsculas en inglés, tenemos un número máximo teórico de combinaciones de 10^26, por lo que para el peor caso teórico, es posible que necesitemos algunas heurísticas. Sin embargo, la mayoría de criptaritmos prácticos tienen mucho menos de 26 letras únicas, por lo que el caso normal probablemente estará limitado por n a menos de 10, lo que también es bastante razonable para una computadora.

+0

fuerza bruta puede ser bueno para un caso particular, ¿qué hay de cuando debe trabajar para cualquier entrada que se especifica adecuadamente dentro de los límites de? –

+0

Eso fue lo que respondí. Para cualquier entrada general, podemos encontrar el peor caso posible para una búsqueda de fuerza bruta. Si queremos una solución estricta, ¡es 10 !, si permitimos duplicados, es 10^26. – Christoffer

1

Bueno, trate de escribirlo como una lista de funciones:

SEND 
MORE 
----+ 
MONEY 

Si recuerdo mi matemáticas de la escuela inferior, esto debería ser:

Y = (D+E) mod 10 
E = ((N+R) + (D+E)/10) mod 10 
... 
+0

¡tus principios son correctos! así es como es, pero me pregunto cómo hacerlo de una manera genérica como solucionador ... –

1

Aquí es un método eficiente de la fuerza bruta que los ciclos a través de todas las posibilidades recursivamente, pero también toma nota de la estructura del problema particular para atajar el problema.

Los primeros argumentos para cada método representan valores de prueba para cada rama, los argumentos v1, v2, etc. son los valores que aún deben asignarse y se pueden pasar en cualquier orden . el método es eficiente porque tiene un máximo de 8x7x5 posibles soluciones de prueba en lugar de las 10!/ 2 posibles soluciones por la fuerza bruta

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void MESDYNR(int m, int s, int e, int d, int y, int n, int r, int v1, int v2, int v3) 
     { 
      // Solve for O in hundreds position 
      // "SEND" + "M?RE" = "M?NEY" 
      int carry = (10 * n + d + 10 * r + e)/100; 
      int o = (10 + n - (e + carry))%10; 

      if ((v1 == o) || (v2 == o) || (v3 == o)) 
      { 
       // check O is valid in thousands position 
       if (o == ((10 + (100 * e + 10 * n + d + 100 * o + 10 * r + e)/1000 + m + s) % 10)) 
       { 
        // "SEND" + "MORE" = "MONEY" 
        int send = 1000 * s + 100 * e + 10 * n + d; 
        int more = 1000 * m + 100 * o + 10 * r + e; 
        int money = 10000 * m + 1000 * o + 100 * n + 10 * e + y; 

        // Chck this solution 
        if ((send + more) == money) 
        { 
         Console.WriteLine(send + " + " + more + " = " + money); 
        } 
       } 
      } 
     } 

     static void MSEDYN(int m, int s, int e, int d, int y, int n, int v1, int v2, int v3, int v4) 
     { 
      // Solve for R 
      // "SEND" + "M*?E" = "M*NEY" 
      int carry = (d + e)/10; 
      int r = (10 + e - (n + carry)) % 10; 

      if (v1 == r) MESDYNR(m, s, e, d, y, n, r, v2, v3, v4); 
      else if (v2 == r) MESDYNR(m, s, e, d, y, n, r, v1, v3, v4); 
      else if (v3 == r) MESDYNR(m, s, e, d, y, n, r, v1, v2, v4); 
      else if (v4 == r) MESDYNR(m, s, e, d, y, n, r, v1, v2, v3); 
     } 

     static void MSEDY(int m, int s, int e, int d, int y, int v1, int v2, int v3, int v4, int v5) 
     { 
      // Pick any value for N 
      MSEDYN(m, s, e, d, y, v1, v2, v3, v4, v5); 
      MSEDYN(m, s, e, d, y, v2, v1, v3, v4, v5); 
      MSEDYN(m, s, e, d, y, v3, v1, v2, v4, v5); 
      MSEDYN(m, s, e, d, y, v4, v1, v2, v3, v5); 
      MSEDYN(m, s, e, d, y, v5, v1, v2, v3, v4); 
     } 

     static void MSED(int m, int s, int e, int d, int v1, int v2, int v3, int v4, int v5, int v6) 
     { 
      // Solve for Y 
      // "SE*D" + "M**E" = "M**E?" 
      int y = (e + d) % 10; 

      if (v1 == y) MSEDY(m, s, e, d, y, v2, v3, v4, v5, v6); 
      else if (v2 == y) MSEDY(m, s, e, d, y, v1, v3, v4, v5, v6); 
      else if (v3 == y) MSEDY(m, s, e, d, y, v1, v2, v4, v5, v6); 
      else if (v4 == y) MSEDY(m, s, e, d, y, v1, v2, v3, v5, v6); 
      else if (v5 == y) MSEDY(m, s, e, d, y, v1, v2, v3, v4, v6); 
      else if (v6 == y) MSEDY(m, s, e, d, y, v1, v2, v3, v4, v5); 
     } 

     static void MSE(int m, int s, int e, int v1, int v2, int v3, int v4, int v5, int v6, int v7) 
     { 
      // "SE**" + "M**E" = "M**E*" 
      // Pick any value for D 
      MSED(m, s, e, v1, v2, v3, v4, v5, v6, v7); 
      MSED(m, s, e, v2, v1, v3, v4, v5, v6, v7); 
      MSED(m, s, e, v3, v1, v2, v4, v5, v6, v7); 
      MSED(m, s, e, v4, v1, v2, v3, v5, v6, v7); 
      MSED(m, s, e, v5, v1, v2, v3, v4, v6, v7); 
      MSED(m, s, e, v6, v1, v2, v3, v4, v5, v7); 
      MSED(m, s, e, v7, v1, v2, v3, v4, v5, v6); 
     } 


     static void MS(int m, int s, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8) 
     { 
      // "S***" + "M***" = "M****" 
      // Pick any value for E 
      MSE(m, s, v1, v2, v3, v4, v5, v6, v7, v8); 
      MSE(m, s, v2, v1, v3, v4, v5, v6, v7, v8); 
      MSE(m, s, v3, v1, v2, v4, v5, v6, v7, v8); 
      MSE(m, s, v4, v1, v2, v3, v5, v6, v7, v8); 
      MSE(m, s, v5, v1, v2, v3, v4, v6, v7, v8); 
      MSE(m, s, v6, v1, v2, v3, v4, v5, v7, v8); 
      MSE(m, s, v7, v1, v2, v3, v4, v5, v6, v8); 
      MSE(m, s, v8, v1, v2, v3, v4, v5, v6, v7); 
     } 

     static void Main(string[] args) 
     { 
      // M must be 1 
      // S must be 8 or 9 
      DateTime Start = DateTime.Now; 
      MS(1, 8, 2, 3, 4, 5, 6, 7, 9, 0); 
      MS(1, 9, 2, 3, 4, 5, 6, 7, 8, 0); 
      Console.WriteLine((DateTime.Now-Start).Milliseconds); 
      return; 
     } 
    } 
} 
Cuestiones relacionadas