Very Nice Friedman Numbers

13

Um número de Friedman é um número inteiro positivo que é igual a uma expressão não trivial que usa seus próprios dígitos em combinação com as operações +, -, *, /, ^, parênteses e concatenação.

Um número agradável de Friedman é um número inteiro positivo que é igual a uma expressão não trivial que usa seus próprios dígitos em combinação com as mesmas operações, com os dígitos em sua ordem original.

Um Número Friedman Muito Bom (VNFN), que estou inventando aqui, é um Número Friedman Agradável, que pode ser escrito sem as partes menos bonitas (na minha opinião) de tal expressão. Parênteses, concatenação e negação unária não são permitidos.

Para esse desafio, há três maneiras possíveis de escrever uma expressão sem parênteses.

Prefixo: Isso é equivalente à associatividade à esquerda. Este tipo de expressão é gravado com todos os operadores à esquerda dos dígitos. Cada operador se aplica às duas expressões a seguir. Por exemplo:

*+*1234 = *(+(*(1,2),3),4) = (((1*2)+3)*4) = 20

Um VNFN que pode ser escrito dessa maneira é 343:

^+343 = ^(+(3,4),3) = ((3+4)^3) = 343

Postfix: Isso é equivalente à associatividade correta. É como a notação de prefixo, exceto que a operação vai para a direita dos dígitos. Cada operador se aplica às duas expressões anteriores. Por exemplo:

1234*+* = (1,(2,(3,4)*)+)* = (1*(2+(3*4))) = 14

Um VNFN que pode ser escrito dessa maneira é 15655:

15655^+** = (1,(5,(6,(5,5)^)+)*)* = (1*(5*(6+(5^5)))) = 15655

Infix: a notação Infix usa a ordem padrão de operações para as cinco operações. Para os propósitos do desafio, essa ordem de operações será definida da seguinte forma: Coloque entre parênteses ^primeiro, à direita associativamente. Então, entre parênteses *e /simultaneamente, saiu associativamente. Por fim, entre parênteses +e -simultaneamente, deixados associativamente.

1-2-3 = (1-2)-3 = -4
2/3*2 = (2/3)*2 = 4/3
2^2^3 = 2^(2^3) = 256
1^2*3+4 = (1^2)*3+4 = 7

Um VNFN que pode ser escrito dessa maneira é 11664:

1*1*6^6/4 = (((1*1)*(6^6))/4) = 11664

Desafio: dado um número inteiro positivo, se ele puder ser expresso como uma expressão não trivial de seus próprios dígitos em notação de prefixo, infixo ou postfix, produza essa expressão. Caso contrário, não produza nada.

Esclarecimentos: Se várias representações forem possíveis, você poderá gerar qualquer subconjunto não vazio delas. Por exemplo, 736 é um VNFN:

+^736 = 736
7+3^6 = 736

+^736, 7+3^6ou ambos seriam saídas aceitáveis.

Uma expressão "trivial" significa aquela que não usa nenhum operador. Isso é relevante apenas para números de um dígito e significa que os números de um dígito não podem ser VNFNs. Isso é herdado da definição de um número de Friedman.

As respostas devem ser executadas em segundos ou minutos em entradas inferiores a um milhão.

Relacionado.

IO: Regras padrão de IO. Programa completo, função, verbo ou similar. STDIN, linha de comando, argumento da função ou similar. Para a saída de "Nothing", a string vazia, uma linha em branco nullou similar e uma coleção vazia são boas. A saída pode ser uma sequência delimitada com um caractere que não pode estar em uma representação ou pode ser uma coleção de sequências.

Exemplos:

127
None

343
^+343

736
736^+
7+3^6

2502
None

15655
15655^+**

11664
1*1*6^6/4
1^1*6^6/4

5
None

Pontuação: Este é o código de golfe. Menos bytes ganha.

Além disso, se você encontrar um, forneça um novo número Friedman muito bom na sua resposta.

isaacg
fonte
*(+(*(1,2),3,4)está faltando um parêntese próximo, depois,3
Sparr 15/05
Qual é o limite para "em segundos ou minutos"? Ainda faltam quatro horas ... muitos ... minutos.
Não que Charles seja
@NotthatCharles 4 horas é demais. Digamos 1 hora na minha máquina, com algum espaço de manobra. Sobre os números com vários dígitos, isso é o que eu estava referindo-se pela concatenação emParentheses, concatenation and unary negation are disallowed.
isaacg

Respostas:

5

Perl, 345 334 318 293 263 245B

$_='$_=$i=pop;$c=y///c-1;sub f{say if$c&&$i==eval pop=~s/\^/**/gr}A$m)$1$4"})};f"("x$c.$m}globOx$c.$i;A$1$4($m"})};f$m.")"x$c}glob$i.Ox$c;map{f$_}glob joinO,/./g';s!O!"{+,-,*,/,^}"!g;s!A!'map{m{(\d)((?R)|(\d)(?{$m=$3}))(.)(?{$m="'!ge;s!d!D!;eval

Ligue com perl -M5.10.0 scratch.pl 736


Resultados

Os primeiros resultados que encontrei são:

^+343
736^+
7+3^6
^+/3125
^+^3125
/^+-11664
/^--11664
1-1+6^6/4
/^++14641
^^++14641
1+5^6/1-8
1+5^6^1-8
1+5^6-2-2
1+5^6-2^2
1+5^6+2-4
1+5^6+4^2
-^+^16377
-^-+16377
/^+^16384
/^-+16384

Explicação

Totalmente não-destruído

Tentei me repetir o máximo possível para facilitar o golfe mais tarde.

#!perl
use 5.10.0;

$_ = $input = pop;

# y///c counts characters in $_
$count = y///c - 1;

sub f {
    say if $count && $input == eval pop =~ s/\^/**/gr
}

# PREFIX
map {
    m{                            # Parses *^+1234
        (\D)                      # $1 = first symbol
        (
            (?R)                  # RECURSE
        |
            (\d)(?{               # $3 = first digit
                $match=$3
            })
        )
        (.)(?{                    # $4 = last digit
            $match="$match)$1$4"
        })
    }x;
    f "(" x $count . $match
}
    # glob expands '{0,1}{0,1}' into 00,01,10,11
    glob "{+,-,*,/,^}" x $count . $input;

# POSTFIX
map {
    m{(\d)((?R)|(\d)(?{$match=$3}))(.)(?{$match="$1$4($match"})};
    f $match. ")" x $count
}
    glob $input . "{+,-,*,/,^}" x $count;

# INFIX
# /./g splits $_ into characters
map { f $_} glob join "{+,-,*,/,^}", /./g

Como é jogado

  • Remova espaços em branco e comentários e substitua todos os vars pela versão de 1 caractere
  • Agrupar o programa em $_=q! ... !;eval
  • Extraia as cordas e substitua-as depois.

Isso fornece algo assim, do qual você pode remover as quebras de linha do resultado:

$_='
    $_=$i=pop;
    $c=y///c-1;
    sub f{say if$c&&$i==eval pop=~s/\^/**/gr}
    A$m)$1$4"})};f"("x$c.$m}globOx$c.$i;
    A$1$4($m"})};f$m.")"x$c}glob$i.Ox$c;
    map{f$_}glob joinO,/./g
';
s!O!"{+,-,*,/,^}"!g;
s!A!'map{m{(\d)((?R)|(\d)(?{$m=$3}))(.)(?{$m="'!ge;
s!d!D!;
eval
alexander-brett
fonte
Obrigado pela resposta e parabéns por estar em primeiro lugar. Em greves amplas, como isso funciona?
Isaacg 14/05
Eu não sei perl, mas parece que é possível extrair as 3 ocorrências }globe salvar alguns bytes.
Isaacg
s!B!}glob!g;BBB-> 15B; }glob}glob}glob-> 15B :) #
211 alexander-brett #
Droga, tão perto.
Isaacg
4

Somente Ruby 2.1.5 - 213 220 238 + 9 = 247

Não sei como Ruby vence Perl, mas aqui está ...

Execute isso com um sinalizador -rtimeout (e -W0 ou envie seu stderr para outro lugar).

Para tornar isso um pouco mais robusto, substitua send([].methods[81],z-1)por repeated_permutation(z-1)e marque um caractere extra (portanto, 248 ).

g=$*[0].split //
exit if 2>z=g.size
d=->a,s{$><<a*''&&exit if$*[0].to_i==timeout(2){eval"#{(s*'').gsub(?^,'**')}"}rescue p}
l,r=[?(]*z,[?)]*z
%w{* / + - ^}.send([].methods[81],z-1){|o|d[m=g.zip(o),m]
d[g+o,l.zip(m)+r]
d[o+g,l+g.zip(r,o)]}

Basicamente, passe por todas as permutações de operadores e tente infix, postfix e prefixo nessa ordem. O dmétodo usa evalno segundo parâmetro para executar os cálculos, capturando quaisquer exceções DivideByZero ou Overflow.

Você precisa enviar stderr para / dev / null, porém, ou evalàs vezes imprimirá avisos como (eval):1: warning: in a**b, b may be too big.

Enquanto eu criava esse jogo, encontrei uma maneira de salvar três caracteres!

Ungolfed (princípios desatualizados, mas semelhantes):

input = $*[0]
digits = input.split //
num_digits = digits.size
exit if 2 > num_digits # one-digit numbers should fail

def print_if_eval print_array, eval_array
  # concatenate the array and replace ^ with **
  eval_string = (eval_array * '').gsub(?^, '**') 
  val = eval(eval_string)
  if input.to_i == val
    $><<print_array*''
    exit
  end
rescue
  # this catches any DivideByZero or Overflow errors in eval.
end
# technically, this should be * (num_digits - 1), but as long as we 
# have AT LEAST (num_digits - 1) copies of the operators, this works
operators = %w{* / + - ^} * num_digits
left_parens = ['('] * num_digits
right_parens = [')'] * num_digits
operators.permutation(num_digits-1) { |op_set|
  # infix
  # just uses the native order of operations, so just zip it all together
  # 1+2-3*4/5^6
  print_if_eval(digits.zip(op_set),
                digits.zip(op_set))

  # postfix
  # leftparen-digit-operator, repeat; then add right_parens
  # (1+(2-(3*(4/(5^(6))))))
  # 
  print_if_eval(digits+op_set,
                (left_parens.zip(digits, op_set) + right_parens))

  # prefix
  # leftparens; then add digit-rightparen-operator, repeat
  # ((((((1)+2)-3)*4)/5)^6)
  print_if_eval(op_set+digits,
                left_parens + digits.zip(right_parens, op_set))
}

Changelog

247 fez esse trabalho para números maiores, em vez de atingir o tempo limite.

220 eliminaram três caracteres declarando matrizes paren e corrigiram um erro em que números de um dígito eram considerados VNFNs

213 confirmação inicial

Não que Charles
fonte
Ótima solução - completa magia negra para mim! Acho que o ruby ​​vence o Perl, pois possui funções de zip e permutação integradas.
Alexander-brett 15/05
@ alexander-brett melhor? a.zip(b,c)retorna uma matriz de matrizes como [ [a[0],b[0],c[0]],[a[1],b[1],c[1]], etc.]e ['hi', 'there']*''apenas concatena a representação de string dos valores da matriz.
Não que Charles
oh, e [a,b]*3rende[a,b,a,b,a,b]
Não que Charles seja o
1

MATLAB (435 b)

n=input('');b=str2num(fliplr(num2str(n)));l=floor(log(b)/log(10));a=unique(nchoosek(repmat('*+-/^', 1,5), l), 'rows');for k=1:numel(a(:,1)),for j=0:2,c=strcat((j>1)*ones(l)*'(',mod(b,10)+48);for i=1:l,c=strcat(c,a(k,i),(j<1)*'(',mod(floor(b/10^i),10)+48,(j>1)*')'); end,c=strcat(c,(j<1)*ones(l)*')');if eval(c(1,:))==n,fprintf('%s%s%s%s\n',c(1,1:(j==1)*numel(c(1,:))),fliplr(a(k,1:(j>1)*l)),(j~=1)*num2str(n),a(k,1:(j<1)*l));end,end,end

tente aqui

http://octave-online.net/

Abr001am
fonte
ainda mais melhorias são necessárias
Abr001am 08/0515
as pessoas não são habituais com o matlab aqui?
Abr001am 15/05
0

Python 2, 303 bytes

Experimente online

from itertools import*
n=input()
l=len(n)-1
E=eval
for c in product('+-*/^',repeat=l):
 L=lambda x,y:x.join(map(y.join,zip(n,c+('',)))).replace('^','**')
 C=''.join(c)
 try:
    if`E(L('',''))`==n:print L('','')
    if`E('('*-~l+L('',')'))`==n:print C[::-1]+n
    if`E(L('(','')+')'*l)`==n:print n+C
 except:pass

A saída do infix conterá em **vez de ^. Se isso não for permitido, .replace('**','^')ocorrerá e adicionará outros 18 bytes

Explicação:

# get all possible combinations of operators (with repetitions)
product('+-*/^',repeat=l)  

# create string from input and operators like
# if passed '(' and '' will return (a+(b+(c
# if passed '' and ')' will return a)+b)+c)
# if passed '' and '' will return a+b+c
lambda x,y:x.join(map(y.join,zip(n,c+('',)))).replace('^','**')

# evaluate infix
E(L('',''))
# evaluate prefix
E('('*-~l+L('',')')) 
# evaluate postfix
E(L('(','')+')'*l)
# all evals need to be inside try-except to handle possible 0 division

# prefix output is need to be swapped (which IMO is not needed)
n:print C[::-1]+n
Gambá morto
fonte