Очень хорошие номера Фридмана


13

Фридман Число является положительным целым числом, которое равно нетривиальной выражение , которое использует свои собственные цифры в сочетании с операциями +, -, *, /, ^, круглые скобки и конкатенации.

Хорошее число Фридмана - это положительное целое число, равное нетривиальному выражению, которое использует свои собственные цифры в сочетании с теми же операциями, причем цифры находятся в их первоначальном порядке.

Очень хороший номер Фридмана (VNFN), который я здесь придумываю, - это хороший номер Фридмана, который можно записать без менее симпатичных (на мой взгляд) частей такого выражения. Круглые скобки, конкатенация и унарное отрицание запрещены.

Для этой задачи есть три возможных способа написания выражения без скобок.

Префикс: это эквивалентно левой ассоциативности. Этот тип выражения пишется со всеми операторами слева от цифр. Каждый оператор применяется к следующим двум выражениям. Например:

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

VNFN, который можно записать так: 343:

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

Постфикс: это эквивалентно правой ассоциативности. Это похоже на префиксную запись, за исключением того, что операция идет справа от цифр. Каждый оператор применяется к двум предыдущим выражениям. Например:

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

VNFN, который можно записать так: 15655:

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

Infix: для обозначения Infix используется стандартный порядок операций для пяти операций. Для целей задачи этот порядок операций будет определен следующим образом: ^сначала поставьте скобки , ассоциативно справа. Затем заключите в скобки *и /одновременно оставьте ассоциативно. Наконец, заключите в скобки +и -одновременно оставьте ассоциативно.

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

VNFN, который можно записать так: 11664:

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

Задача: если задано положительное целое число, если оно может быть выражено как нетривиальное выражение своих собственных цифр в префиксной, инфиксной или постфиксной нотации, выведите это выражение. Если нет, ничего не выводить.

Пояснения: если возможно несколько представлений, вы можете вывести любое непустое их подмножество. Например, 736 является VNFN:

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

+^736, 7+3^6 Или оба все были бы приемлемые выходы.

«Тривиальное» выражение означает выражение, которое не использует никаких операторов. Это относится только к однозначным числам и означает, что однозначные числа не могут быть номерами VNFN. Это унаследовано от определения числа Фридмана.

Ответы должны запускаться в секундах или минутах на входах менее миллиона.

Связанный.

IO: Стандартные правила IO. Полная программа, функция, глагол или подобное. STDIN, командная строка, аргумент функции или аналогичный. Для вывода «Nothing» подойдет пустая строка, пустая строка nullили аналогичная и пустая коллекция. Вывод может быть строкой, разделенной символом, который не может быть в представлении, или может быть набором строк.

Примеры:

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

Подсчет очков: это код гольф. Побеждает несколько байтов.

Также, если вы найдете такой номер, укажите в своем ответе новый номер Very Nice Friedman.


*(+(*(1,2),3,4)отсутствует один близкий парень, после,3
Спарр

Какая кепка на "в секундах или минутах"? Четыре часа все еще в ... много ... минут.
Не то, что Чарльз

@NotthatCharles 4 часа это слишком много. Допустим, 1 час на моей машине, с какой-то комнатой для маневра. Что касается многозначных чисел, это то, к чему я обращался при конкатенации вParentheses, concatenation and unary negation are disallowed.
Исаак

Ответы:


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

Позвонить с perl -M5.10.0 scratch.pl 736


Результаты

Первые несколько результатов, которые я нашел:

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

объяснение

Полностью безгольфированный

Я старался повторять как можно больше, чтобы облегчить дальнейшую игру в гольф.

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

Как это в гольф

  • Удалить пробелы и комментарии и заменить все переменные 1-символьной версией
  • Обернуть программу в $_=q! ... !;eval
  • Извлекайте строки и подставляйте их потом.

Это дает что-то вроде этого, из которого вы можете удалить разрывы строк для результата:

$_='
    $_=$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

Спасибо за ответ и поздравляю с тем, что вы на первом месте. В общих чертах, как это работает?
Исаак

Я не знаю Perl, но похоже, что можно извлечь 3 вхождения }globи сохранить несколько байтов.
Исаак

s!B!}glob!g;BBB-> 15B; }glob}glob}glob-> 15B :)
Александр-Бретт

Черт, так близко.
Исаак

4

Только Ruby 2.1.5 - 213 220 238 + 9 = 247

Не уверен, как Руби побеждает Perl, но здесь вы идете ...

Запустите это с флагом -rtimeout (и либо -W0, либо отправьте ваш stderr в другое место).

Для того, чтобы сделать это немного более надежным, замените send([].methods[81],z-1)с repeated_permutation(z-1)и набрать дополнительный характер (так, 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)]}

По сути, пройдите все перестановки операторов и попробуйте infix, postfix и prefix в указанном порядке. d методе используетсяeval на второй параметр для выполнения вычислений, ловить каких - либо исключений DivideByZero или переполнения.

Вам нужно отправить stderr в / dev / null, иначе evalиногда будут выводиться предупреждения(eval):1: warning: in a**b, b may be too big .

В то время как я придумал это безрассудство, я нашел способ спасти три символа!

Ungolfed (устаревшие, но похожие принципы):

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

Изменения

247 сделали эту работу для больших чисел, а не для тайм-аута.

220 сбрил три символа, объявив парные массивы, и исправил ошибку, когда однозначные числа считались VNFN

213 начальный коммит


Отличное решение - полная черная магия для меня! Я полагаю, что ruby ​​превосходит Perl, поскольку он имеет встроенные функции zip и перестановки.
Александр-Бретт

@ Александр-Бретт лучше? a.zip(b,c)возвращает массив массивов вроде [ [a[0],b[0],c[0]],[a[1],b[1],c[1]], etc.]и ['hi', 'there']*''просто объединяет строковое представление значений массива.
Не то, что Чарльз

о, и [a,b]*3дает[a,b,a,b,a,b]
не то, что Чарльз

1

MATLAB (435 б)

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

попробуйте здесь

http://octave-online.net/


еще больше улучшений необходимо
Abr001am

люди не привыкли к Matlab здесь?
Abr001am

0

Python 2, 303 байта

Попробуйте онлайн

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

Вывод инфикса будет содержать **вместо ^. Если это не разрешено,.replace('**','^') произойдет и добавит еще 18 байтов

Объяснение:

# 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.