Haz matemáticas con mínimos fósforos

15

Meta-fondo

Esto se estableció como una pregunta sobre Puzzling , y la reacción instantánea fue "bueno, alguien lo resolverá por computadora". Hubo un debate sobre cuán complejo debería ser un programa para resolver esto. Bueno, "qué tan complejo tiene que ser este programa" es más o menos la definición de de , ¿entonces quizás PPCG pueda resolver el problema?

Antecedentes

Una ecuación de fósforo es básicamente una ecuación matemática normal, pero donde los dígitos y los operadores se construyen físicamente colocando fósforos en una mesa. (La principal característica relevante de los fósforos aquí es que son bastante rígidos y tienen una longitud constante; a veces las personas usan otros objetos, como hisopos de algodón).

Para este desafío, no necesitamos definir reglas específicas sobre cómo se organizan los matchsticks (como lo hace el desafío vinculado); más bien, solo nos preocupamos por cuántas coincidencias necesitaremos para representar una expresión que se evalúe en un número dado.

La tarea

Aquí hay un alfabeto de dígitos y operadores matemáticos que puede usar, cada uno con un costo en fósforos:

  • 0, que cuesta 6 fósforos
  • 1, que cuesta 2 fósforos
  • 2, que cuesta 5 fósforos
  • 3, que cuesta 5 fósforos
  • 4, costando 4 fósforos
  • 5, que cuesta 5 fósforos
  • 6, que cuesta 6 fósforos
  • 7, que cuesta 3 fósforos
  • 8, que cuesta 7 fósforos
  • 9, que cuesta 6 fósforos
  • +, que cuesta 2 fósforos
  • -, que cuesta 1 fósforo
  • ×, que cuesta 2 fósforos

(Usted puede representarse ×como *en la producción de su programa si lo desea, con el fin de evitar la necesidad de utilizar caracteres no ASCII. En la mayoría de las codificaciones, ×ocupa más bytes que *, por lo que me imagino que la mayoría de los programas que desee tomar ventaja de este margen de maniobra .)

Debe escribir un programa que tome un entero no negativo como entrada (por cualquier medio razonable ) y produzca una expresión que evalúe a ese entero como salida (nuevamente por cualquier medio razonable). Además, la expresión debe ser no trivial: debe contener al menos un operador +, -o ×. Finalmente, la expresión que genere debe ser la más barata (o vinculada a la más barata) en términos de costo total de fósforos, entre todas las salidas que de lo contrario cumplen con la especificación.

Aclaraciones

  • Puede formar números de varios dígitos mediante la salida de múltiples dígitos en una fila (por ejemplo, 11-1es una salida válida para producir 10). Para ser completamente precisos, el número resultante se interpreta en decimal. Este tipo de concatenación no es una operación que funcione en resultados intermedios; solo en dígitos literales que aparecen en la expresión original.
  • A los efectos de este desafío. +, -y ×son operadores infijos; necesitan una discusión a su izquierda y a su derecha. No está permitido usarlos en la posición de prefijo como +5o -8.
  • No tiene paréntesis (ni ninguna otra forma de controlar la precedencia) disponible. La expresión se evalúa de acuerdo con las reglas de precedencia predeterminadas típicas (las multiplicaciones ocurren primero, y luego las sumas y restas se evalúan de izquierda a derecha).
  • No tiene acceso a ningún operador matemático o constantes que no sean los mencionados anteriormente; Las soluciones de "pensamiento lateral" a menudo son aceptadas en Puzzling, pero no tiene sentido exigir que una computadora las presente, y aquí en PPCG, nos gusta que sea objetivo si una solución es correcta o no.
  • Se aplican las reglas habituales de desbordamiento de enteros: su solución debe poder funcionar para enteros arbitrariamente grandes en una versión hipotética (o tal vez real) de su idioma en la que todos los enteros están ilimitados de forma predeterminada, pero si su programa falla en la práctica debido a la implementación no admite enteros tan grandes, eso no invalida la solución.
  • Si usa el mismo dígito u operador más de una vez, debe pagar el costo de su fósforo cada vez que lo usa (porque, obviamente, no puede reutilizar los mismos fósforos físicos en dos ubicaciones diferentes en la tabla).
  • No hay límite de tiempo; Las soluciones de fuerza bruta son aceptables. (Aunque si tiene una solución que es más rápida que la fuerza bruta, no dude en publicarla incluso si es más larga; ver cómo comparar enfoques alternativos siempre es interesante).
  • Aunque nunca es necesario escribir una explicación de su código , es probable que sea una buena idea; soluciones de menudo son muy difíciles de leer (especialmente para las personas que no están familiarizadas con el idioma en el que están escritas), y puede ser difícil evaluar (y por lo tanto votar) una solución a menos que comprenda cómo funciona.

Condición de victoria

Como un desafío de , las respuestas con menos bytes se consideran mejores. Sin embargo, como de costumbre, siéntase libre de publicar respuestas con diferentes enfoques, o en idiomas específicos, incluso si son más detallados que ciertos otros idiomas; El objetivo del golf es realmente ver hasta qué punto puede optimizar un programa en particular, y hacer las cosas de esta manera nos da muchos programas potenciales para optimizar. Por lo tanto, no se desanime si alguien presenta una solución utilizando un enfoque completamente diferente, o un lenguaje completamente diferente, y obtiene una respuesta mucho más corta; bien puede ser que su respuesta esté mejor optimizada y muestre más habilidad, y los votantes en PPCG a menudo aprecian eso.

Comunidad
fuente
Dios, ¿cuál es el número más alto que necesitamos manejar? Mi intento actual no iría más allá de ... tal vez 20 en TIO.
Magic Octopus Urn
@carusocomputing: arbitrariamente alto en teoría , pero si no puedes superar los 20 en un tiempo razonable en la práctica, eso es completamente aceptable.
44
¿Tienes algún caso de prueba?
Lucas
Realmente desearía que esta fuera una sola operación, extendida contra múltiples competiciones. La multiplicación es un problema divisor, pero sumar y restar realmente complica las cosas. Tengo una solución que funciona, pero no para la suma y la resta; hacer que funcione perfectamente será tedioso.
Magic Octopus Urn
@carusocomputing: Entonces, quizás te interese este desafío . Sospecho que el desafío con la multiplicación solo es significativamente diferente y requeriría técnicas de solución bastante diferentes para obtener una buena puntuación.

Respuestas:

1

Python2, 1̶9̶8̶ ̶b̶y̶t̶e̶s̶ 182 bytes gracias a math_junkie

def f(n,c=dict(zip('0123456789+-*',map(int,'6255456376212'))),e=[(0,'')]):
 while 1:
    v=(m,s)=min(e);e.remove(v)
    try:
     if eval(s)==n:return s
    except:0
    e+=[(m+c[x],s+x)for x in c]

Este algoritmo no hace nada para excluir las versiones de prefijo de +y -, pero serán peores o iguales y aparecerán más adelante en la búsqueda, sus contrapartes de infijo. Debido a que utiliza el argumento de la palabra clave de manera emutable, dará resultados no válidos si se llama varias veces por sesión. Para solucionar esto, use en f(n, e=[(0,'')])lugar de solo f(n). Tenga en cuenta que las sangrías de cuatro espacios representan pestañas, por lo que esto solo funcionará con Python 2.

También tengo una versión optimizada y sin golf que se ejecuta rápidamente incluso para números bastante grandes:

from heapq import heappop, heappush

def f(n):
    digits = list('0123456789')
    ops =['+','-','*','']
    costs = dict(zip(digits + ops, [6,2,5,5,4,5,6,3,7,6,2,1,2,0]))
    expressions = [(costs[d], abs(n - int(d)), int(d), d) for d in digits[1:]]
    seen = set()
    while 1:
        cost, d, k, expression = heappop(expressions)
        if d == 0:
            return expression
        for op in ops:
            if op in '+-' and k in seen:
                continue
            for digit in digits:
                if op and digit == '0':
                    continue
                expression1 = expression + op + digit
                k1 = eval(expression1)
                d1 = abs(n - k1)
                if d1 == 0:
                    return expression1
                heappush(expressions, (cost+costs[op]+costs[digit], d1, k1, expression1))
        seen.add(k)
user1502040
fuente
Algunos campos de golf menores sugeridos: TIO (182 bytes)
adicto a las matemáticas el
1

PHP, 241 bytes

Versión en línea

function m($i){for(;$s<strlen($i);)$e+="6255456376"[$i[$s++]];return$e;}foreach($r=range(0,2*$a=$argv[1])as$v)foreach($r as$w)$x[$v+$w]["$v+$w"]=$x[$v*$w]["$v*$w"]=1+$x[$v-$w]["$v-$w"]=m("$v")+m("$w")+1;echo array_search(min($x[$a]),$x[$a]);

Descompostura

function m($i){
    for(;$s<strlen($i);)$e+="6255456376"[$i[$s++]];return$e; #return the count of the matchstick for an integer
}

foreach($r=range(0,2*$a=$argv[1])as$v) # limit to an input to 300 in the online version
foreach($r as$w)
       $x[$v+$w]["$v+$w"]=  #fill the 2D array in the form [result][expression] = count matchsticks
       $x[$v*$w]["$v*$w"]=
       1+$x[$v-$w]["$v-$w"]=
       m("$v")+m("$w")+1;
echo $k=array_search(min($x[$a]),$x[$a]); # Output expression with a minium of matchsticks
echo"\t".$x[$a][$k]; #optional Output of the count of the matchsticks

Camino con un poco mejor rendimiento

function m($i){
for(;$s<strlen($i);)
$e+="6255456376"[$i[$s++]];return$e;} #return the count of the matchstick for an integer
foreach($r=range(0,2*$a=$argv[1])as$v)
foreach($r as$w){$c=m("$v")+m("$w")+1;
if($a==$v+$w)$x["$v+$w"]=1+$c; # fill array if value equal input
if($a==$v*$w)$x["$v*$w"]=1+$c;
if($a==$v-$w)$x["$v-$w"]=$c;}
echo $k=array_search(min($x),$x); # Output expression with a minium of matchsticks
    echo"\t".$x[$k]; #optional Output of the count of the matchsticks

Soporte de enteros negativos

Versión con enteros negativos

function m($i){
    $e=$i<0?1:0; # raise count for negative integers
    for($s=0;$s<strlen($i);)$e+=[6,2,5,5,4,5,6,3,7,6][$i[$s++]];return$e; #return the count of the matchstick for an integer
}
$q=sqrt(abs($argv[1]));
$l=max(177,$q);
$j=range(-$l,$l); # for second loop for better performance
foreach($r=range(min(0,($a=$argv[1])-177),177+$a)as$v) 
foreach($j as$w){$c=m("$v")+m("$w")+1;  
    if($a==$v+$w)$x["$v+$w"]=1+$c; # fill array if value equal input
    if($a==$v*$w)$x["$v*$w"]=1+$c;
    if($a==$v-$w)$x["$v-$w"]=$c;
    if($a==$w-$v)$x["$w-$v"]=$c; # added for integers <0
}
echo $k=array_search(min($x),$x); # Output expression with a minium of matchsticks
echo"\t".$x[$k]; #optional Output of the count of the matchsticks
Jörg Hülsermann
fuente
¡Oh, broche, esto también funciona en números negativos!
Magic Octopus Urn
@carusocomputing en realidad no podría ser que exista una solución con menos coincidencias porque los números negativos solo se suman por sustracción. en estos casos, también debe verificar el valor absoluto y agregar uno
Jörg Hülsermann
No creo que el 333 literal sea aceptable aquí, aunque es probable que pueda solucionarlo haciendo que sea una función de la entrada. (El programa bien podría funcionar mucho más lento, por lo que podría mantener la versión hardcoded para probar.)
1
@ ais523 hecho 333 se reemplaza con 2 * entrada
Jörg Hülsermann
1
Puede cadenas de índice: $e+="6255456376"[$i[$s++]];.
manatwork