Faça matemática com palitos de fósforo mínimos

15

Meta-fundo

Isso foi definido como uma pergunta sobre o Puzzling , e a reação instantânea foi "bem, alguém resolverá isso apenas por computador". Houve um debate sobre o quão complexo seria um programa para resolver isso. Bem, "quão complexo esse programa precisa ser" é praticamente a definição de , então talvez o PPCG possa resolver o problema?

fundo

Uma equação de palito de fósforo é basicamente uma equação matemática normal, mas onde os dígitos e operadores são construídos fisicamente, colocando palitos de fósforo em uma tabela. (A principal característica relevante dos palitos de fósforo aqui é que eles são bastante rígidos e têm um comprimento constante; às vezes as pessoas usam outros objetos, como cotonetes.)

Para esse desafio, não precisamos definir regras específicas para a organização dos palitos de fósforo (como faz o desafio vinculado); em vez disso, apenas nos importamos com quantas palitos de fósforo precisaremos para representar uma expressão que é avaliada para um determinado número.

A tarefa

Aqui está um alfabeto de dígitos e operadores matemáticos que você pode usar, cada um com um custo em palitos de fósforo:

  • 0, custando 6 palitos de fósforo
  • 1, custando 2 palitos de fósforo
  • 2, custando 5 palitos de fósforo
  • 3, custando 5 palitos de fósforo
  • 4, custando 4 palitos de fósforo
  • 5, custando 5 palitos de fósforo
  • 6, custando 6 palitos de fósforo
  • 7, custando 3 palitos de fósforo
  • 8, custando 7 palitos de fósforo
  • 9, custando 6 palitos de fósforo
  • +, custando 2 palitos de fósforo
  • -, custando 1 palito de fósforo
  • ×, custando 2 palitos de fósforo

(Você pode representar ×como *na saída do seu programa, se desejar, para evitar a necessidade de usar caracteres não-ASCII. Na maioria das codificações, ×ocupa mais bytes do que *, e por isso imagino que a maioria dos programas deseje tirar vantagem dessa margem de manobra. .)

Você precisa escrever um programa que use um número inteiro não negativo como entrada (por qualquer meio razoável ) e produza uma expressão que avalie esse número inteiro como saída (novamente por qualquer meio razoável). Além disso, a expressão deve ser não trivial: deve conter, pelo menos, um operador +, -ou ×. Por fim, a expressão que você produz deve ser a mais barata (ou vinculada à mais barata) em termos de custo total do palito de fósforo, entre todas as saídas que, de outra forma, atendem à especificação.

Esclarecimentos

  • Você pode formar números de vários dígitos através da saída de vários dígitos em uma linha (por exemplo, 11-1é uma saída válida para produzir 10). Apenas para ser completamente preciso, o número resultante é interpretado em decimal. Esse tipo de concatenação não é uma operação que funciona com resultados intermediários; somente nos dígitos literais que aparecem na expressão original.
  • Para o propósito deste desafio. +, -, E ×são operadores infixas; eles precisam de uma discussão à esquerda e à direita. Você não pode usá-los na posição de prefixo como +5ou -8.
  • Você não tem parênteses (ou qualquer outra maneira de controlar a precedência) disponível. A expressão é avaliada de acordo com as regras de precedência padrão típicas (as multiplicações ocorrem primeiro e, em seguida, as adições e subtrações são avaliadas da esquerda para a direita).
  • Você não tem acesso a nenhum operador matemático ou constante além dos listados acima; As soluções de "pensamento lateral" são frequentemente aceitas no Puzzling, mas não faz sentido exigir que um computador as crie e, aqui no PPCG, gostamos que seja objetivo se uma solução está correta ou não.
  • As regras usuais de estouro de números inteiros se aplicam: sua solução deve ser capaz de trabalhar com números inteiros arbitrariamente grandes em uma versão hipotética (ou talvez real) do seu idioma, na qual todos os números inteiros são ilimitados por padrão, mas se o seu programa falhar na prática devido à implementação não suporta números inteiros tão grandes que não invalida a solução.
  • Se você usar o mesmo dígito ou operador mais de uma vez, terá que pagar o custo do palito de fósforo cada vez que o usar (porque, obviamente, não é possível reutilizar os mesmos palitos de fósforo físicos em dois locais diferentes na mesa).
  • Não há limite de tempo; soluções de força bruta são aceitáveis. (Embora se você tiver uma solução mais rápida que a força bruta, fique à vontade para publicá-la, mesmo que seja mais longa; ver como as abordagens alternativas se comparam é sempre interessante.)
  • Embora nunca seja necessário escrever uma explicação para o seu código , é provável que seja uma boa ideia; soluções geralmente são muito difíceis de ler (especialmente para pessoas que não estão familiarizadas com o idioma em que estão escritas) e pode ser difícil avaliar (e, portanto, votar) em uma solução, a menos que você entenda como ela funciona.

Condição de vitória

Como um desafio de , respostas com menos bytes são consideradas melhores. No entanto, como sempre, sinta-se à vontade para postar respostas com abordagens diferentes ou em idiomas específicos, mesmo que sejam mais detalhados que outros idiomas; o objetivo do golfe é realmente ver até que ponto você pode otimizar um programa em particular, e fazer as coisas dessa maneira nos oferece muitos programas em potencial para otimizar. Portanto, não desanime se alguém enviar uma solução usando uma abordagem completamente diferente ou um idioma completamente diferente e obter uma resposta muito mais curta; pode ser que sua resposta seja melhor otimizada e mostre mais habilidade, e os eleitores do PPCG geralmente apreciam isso.

Comunidade
fonte
Eita, qual é o número mais alto que precisamos lidar? Minha tentativa atual não iria além de ... talvez 20 no TIO.
Urna Mágica do Polvo
@carusocomputing: Arbitrariamente alto em teoria , mas se você não conseguir superar os 20 em um prazo razoável na prática, isso é totalmente aceitável.
4
Você tem algum caso de teste?
28417 Luke
Eu realmente gostaria que essa fosse uma operação única, espalhada por várias competições. A multiplicação é um problema divisor, mas adicionar adição e subtração realmente complica as coisas. Eu tenho uma solução que funciona, mas não para adição e subtração; fazer esse trabalho perfeitamente será tedioso.
Magic Octopus Urn
@carusocomputing: Você pode estar interessado neste desafio , então. Suspeito que o desafio apenas da multiplicação seja significativamente diferente e exigiria técnicas de solução bastante diferentes para obter uma boa pontuação.

Respostas:

1

Python2, 1̶9̶8̶ ̶b̶y̶t̶e̶s̶ 182 bytes graças 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]

Esse algoritmo não faz nada para excluir versões de prefixo de +e -, mas elas serão piores ou iguais a e aparecerão mais tarde na pesquisa, suas contrapartes de infixo. Como ele usa o argumento de palavra-chave de forma emutável, ele fornecerá resultados inválidos se chamado várias vezes por sessão. Para corrigir isso, use em f(n, e=[(0,'')])vez de apenas f(n). Observe que os recuos com quatro espaços representam guias, portanto, isso funcionará apenas com o Python 2.

Eu também tenho uma versão otimizada e não-gasta, que roda rapidamente, mesmo 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
fonte
Algumas pequenas sugeriu golfs: TIO (182 bytes)
viciado em matemática
1

PHP, 241 bytes

Versão Online

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

Demolir

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

Caminho com um desempenho um pouco melhor

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

Suporte de números inteiros negativos

Versão com números inteiros 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
fonte
Oh snap, isso funciona em números negativos também!
Urna Mágica do Polvo
@carusocomputing não é realmente possível que exista uma solução com menos palitos de fósforo, pois números negativos são adicionados apenas por subtração.
nesses
Eu não acho que o literal 333 seria aceitável aqui, embora você provavelmente possa corrigi-lo, tornando-o alguma função da entrada. (O programa pode também correr muito mais lento, para que você possa manter a versão codificado para testar.)
1
@ ais523 feito 333 é substituído com 2 entradas *
Jörg Hülsermann
1
Você pode cordas índice: $e+="6255456376"[$i[$s++]];.
manatwork