Muy buenos números de Friedman

13

Un número de Friedman es un número entero positivo que es igual a una expresión no trivial que usa sus propios dígitos en combinación con las operaciones +, -, *, /, ^, paréntesis y concatenación.

Un número de Nice Friedman es un número entero positivo que es igual a una expresión no trivial que usa sus propios dígitos en combinación con las mismas operaciones, con los dígitos en su orden original.

Un número de Friedman muy bonito (VNFN), que estoy inventando aquí, es un número de Friedman bonito que se puede escribir sin las partes menos bonitas (en mi opinión) de tal expresión. Los paréntesis, la concatenación y la negación unaria están prohibidos.

Para este desafío, hay tres formas posibles de escribir una expresión sin paréntesis.

Prefijo: Esto es equivalente a asociatividad izquierda. Este tipo de expresión se escribe con todos los operadores a la izquierda de los dígitos. Cada operador se aplica a las siguientes dos expresiones. Por ejemplo:

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

Un VNFN que se puede escribir de esta manera es 343:

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

Postfix: Esto es equivalente a la asociatividad correcta. Es como la notación de prefijo, excepto que la operación va a la derecha de los dígitos. Cada operador se aplica a las dos expresiones anteriores. Por ejemplo:

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

Un VNFN que se puede escribir de esta manera es 15655:

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

Infix: la notación Infix utiliza el orden estándar de operaciones para las cinco operaciones. Para los propósitos del desafío, ese orden de operaciones se definirá de la siguiente manera: ^Primero, paréntesis , derecho asociativo. Luego, entre paréntesis *y /, simultáneamente, se fue asociativamente. Finalmente, entre paréntesis +y -simultáneamente, izquierda asociativamente.

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

Un VNFN que se puede escribir de esta manera es 11664:

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

Desafío: dado un entero positivo, si puede expresarse como una expresión no trivial de sus propios dígitos en notación de prefijo, infijo o postfijo, genera esa expresión. De lo contrario, no envíe nada.

Aclaraciones: si son posibles varias representaciones, puede generar cualquier subconjunto no vacío de ellas. Por ejemplo, 736 es un VNFN:

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

+^736, 7+3^6o ambos serían productos aceptables.

Una expresión "trivial" significa una que no utiliza ningún operador. Esto solo es relevante para números de un dígito, y significa que los números de un dígito no pueden ser VNFN. Esto se hereda de la definición de un número de Friedman.

Las respuestas deben ejecutarse en segundos o minutos en entradas de menos de un millón.

Relacionado.

IO: reglas estándar de IO. Programa completo, función, verbo o similar. STDIN, línea de comando, argumento de función o similar. Para generar "Nothing", la cadena vacía, una línea en blanco nullo similar y una colección vacía están bien. La salida puede ser una cadena delimitada con un carácter que no puede estar en una representación, o puede ser una colección de cadenas.

Ejemplos:

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

Puntuación: Este es el código de golf. Pocos bytes ganan.

Además, si encuentra uno, proporcione un nuevo número Very Nice Friedman en su respuesta.

isaacg
fuente
*(+(*(1,2),3,4)le falta un par cercano, después,3
Sparr
¿Cuál es el límite "en segundos o minutos"? Todavía quedan cuatro horas ... muchos ... minutos.
No es que Charles
@NotthatCharles 4 horas es demasiado. Digamos 1 hora en mi máquina, con algo de margen de maniobra. Acerca de los números de varios dígitos, a eso me Parentheses, concatenation and unary negation are disallowed.
refería

Respuestas:

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

Llamar con perl -M5.10.0 scratch.pl 736


Resultados

Los primeros resultados que encontré son:

^+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

Explicación

Totalmente sin golf

Traté de repetirme lo más posible para facilitar el golf posterior.

#!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

Cómo se juega al golf

  • Elimine espacios en blanco y comentarios y reemplace todos los vars con la versión de 1 carácter
  • Programa envolvente en $_=q! ... !;eval
  • Extraiga cadenas y sustitúyalas luego.

Esto proporciona algo como esto, desde el cual puede eliminar los saltos de línea para el 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
fuente
Gracias por la respuesta, y felicidades por estar en primer lugar. En huelgas amplias, ¿cómo funciona?
isaacg
No sé Perl, pero parece que podría ser posible extraer las 3 ocurrencias de }globy guardar algunos bytes.
isaacg
s!B!}glob!g;BBB-> 15B; }glob}glob}glob-> 15B :)
alexander-brett
Maldición, tan cerca.
isaacg
4

Ruby 2.1.5 solamente - 213 220 238 + 9 = 247

No estoy seguro de cómo Ruby le gana a Perl, pero aquí tienes ...

Ejecute esto con un indicador -rtimeout (y -W0 o envíe su stderr a otra parte).

Para hacer esto un poco más robusto, reemplace send([].methods[81],z-1)con repeated_permutation(z-1)y anote un personaje adicional (entonces, 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)]}

Básicamente, revise todas las permutaciones de operadores e intente infix, postfix y prefix en ese orden. El dmétodo utiliza evalel segundo parámetro para realizar los cálculos, capturando cualquier excepción DivideByZero o Overflow.

Sin embargo, debe enviar stderr a / dev / null, o de lo contrario evala veces imprimirá advertencias como (eval):1: warning: in a**b, b may be too big.

Mientras se me ocurría esta falta de golf, ¡encontré una manera de salvar tres caracteres!

Sin golf (principios anticuados pero similares):

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))
}

Registro de cambios

247 hizo que esto funcione para números más grandes en lugar de agotar el tiempo de espera.

220 recortaron tres caracteres declarando matrices de pares y arreglaron un error en el que los números de un dígito se consideraban VNFN

213 confirmación inicial

No es que Charles
fuente
Gran solución: ¡completa la magia negra para mí! Supongo que Ruby supera a Perl ya que tiene funciones integradas de zip y permutación.
alexander-brett
@ alexander-brett mejor? a.zip(b,c)devuelve una matriz de matrices como [ [a[0],b[0],c[0]],[a[1],b[1],c[1]], etc.]y ['hi', 'there']*''simplemente concatena la representación de cadena de los valores de la matriz.
No es que Charles
ah, y [a,b]*3rinde[a,b,a,b,a,b]
No es que Charles
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

pruébalo aquí

http://octave-online.net/

Abr001am
fuente
aún se necesitan más mejoras
Abr001am
la gente no es habitual con matlab aquí?
Abr001am
0

Python 2, 303 bytes

Pruébalo en línea

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

La salida de infijo contendrá en **lugar de ^. Si esto no está permitido, .replace('**','^')ocurrirá y agregará otros 18 bytes

Explicación:

# 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
Zarigüeya muerta
fuente