Складіть математику з мінімальними запалками


15

Мета-фон

Це було поставлено як питання щодо загадки , і миттєва реакція була "ну хтось просто вирішить це комп'ютером". Була дискусія про те, наскільки складною має бути програма для її вирішення. Що ж, "наскільки складною повинна бути ця програма" - це в значній мірі визначення , тож, можливо, PPCG може вирішити проблему?

Фон

Рівняння сірники в основному нормальне математичне рівняння, але де цифра і оператори будуються фізично, поміщаючи сірники на стіл. (Основна відповідна особливість сірників тут полягає в тому, що вони досить жорсткі і мають постійну довжину; іноді люди використовують замість них інші предмети, наприклад ватні тампони.)

Для цього виклику нам не потрібно визначати конкретні правила того, як влаштовані сірники (як це пов'язане завдання); скоріше, нас просто цікавить, скільки сірників нам знадобиться, щоб представити вираз, який оцінюється на задане число.

Завдання

Ось алфавіт цифр і математичних операторів, якими ви можете скористатися, кожен з яких має вартість у відповідних таблицях:

  • 0, вартістю 6 сірників
  • 1, вартістю 2 сірника
  • 2, вартістю 5 сірників
  • 3, вартістю 5 сірників
  • 4, вартістю 4 сірника
  • 5, вартістю 5 сірників
  • 6, вартістю 6 сірників
  • 7, вартістю 3 сірника
  • 8, вартістю 7 сірників
  • 9, вартістю 6 сірників
  • +, вартістю 2 сірника
  • -, вартість 1 матчу
  • ×, вартістю 2 сірника

(Ви можете уявити , ×як *на виході вашої програми , якщо ви хочете, щоб уникнути необхідності використовувати не-ASCII символи. В більшості кодувань, ×займає більше байт , ніж *, і тому я вважаю , що більшість програм захочуть скористатися цією свободою дій .)

Вам потрібно написати програму, яка приймає негативне ціле число як вхідне (будь-яким розумним способом ) і виробляє вираз, який оцінює це ціле число як вихід (знову ж таки будь-якими розумними засобами). Крім того, вираз має бути нетривіальним: вона повинна містити принаймні один оператор +, -або ×. Нарешті, вираз, який ви виводите, повинен бути найдешевшим (або прив'язаним до найдешевшого) з точки зору загальної вартості відповідника, серед усіх результатів, які в іншому випадку відповідають специфікації.

Роз'яснення

  • Ви можете формувати багатоцифрові числа за допомогою виведення декількох цифр підряд (наприклад 11-1, це дійсний результат для отримання 10). Щоб бути абсолютно точним, отримане число інтерпретується у десяткові. Цей вид конкатенації не є операцією, яка працює на проміжних результатах; лише на буквальних цифрах, які відображаються в оригінальному виразі.
  • Для цього завдання. +, -та ×є операторами фіксації; їм потрібен аргумент зліва і справа. Вам заборонено використовувати їх у позиції префікса, як +5або -8.
  • У вас немає дужок (чи будь-який інший спосіб контролювати пріоритет). Вираз оцінюється за типовими правилами пріоритетності за замовчуванням (множення відбувається спочатку, а потім додавання та віднімання оцінюються зліва направо).
  • Ви не маєте доступу до будь-яких математичних операторів чи констант, окрім перелічених вище; Рішення "бічного мислення" часто приймаються на Puzzling, але не має сенсу вимагати, щоб комп'ютер сам придумував їх, і тут, на PPCG, нам подобається, щоб це було об'єктивним, чи рішення є правильним.
  • Застосовуються звичайні правила переповнення цілих чисел: ваше рішення повинно бути здатне працювати для довільно великих цілих чисел у гіпотетичній (або, можливо, реальній) версії вашої мови, в якій всі цілі числа за замовчуванням не пов'язані, але якщо ваша програма виходить з ладу на практиці через впровадження Не підтримуючи великі цілі числа, це рішення не може визнати недійсним.
  • Якщо ви використовуєте одну і ту ж цифру або оператор більше одного разу, вам доведеться сплачувати її вартість відповідника щоразу, коли ви користуєтесь нею (оскільки, очевидно, ви не можете повторно використовувати одні й ті ж фізичні показники у двох різних місцях таблиці).
  • Немає обмежень у часі; рішення жорстокої сили прийнятні. (Хоча якщо у вас є рішення, яке швидше, ніж груба сила, сміливо публікуйте його, навіть якщо воно довше; бачити, як альтернативні підходи порівнювати завжди цікаво.)
  • Хоча писати пояснення свого коду ніколи не потрібно , це, ймовірно, буде хорошою ідеєю; Рішення з часто важко читати (особливо людям, які не знайомі з мовою, якою вони написані), і це може бути важко оцінити (і таким чином проголосувати) за рішення, якщо ви не зрозумієте, як воно працює.

Стан перемоги

Як виклик з , відповіді з меншою кількістю байтів вважаються кращими. Однак, як завжди, сміливо публікуйте відповіді з різними підходами або певними мовами, навіть якщо вони більш багатослівні, ніж деякі інші мови; мета гольфу - це дійсно побачити, наскільки ви можете оптимізувати певну програму, і робити це таким чином дає нам безліч потенційних програм для оптимізації. Тому не варто відмовлятися, якщо хтось подає рішення, використовуючи зовсім інший підхід або зовсім іншу мову, і отримає набагато коротший відповідь; цілком можливо, що ваша відповідь краще оптимізована і виявляє більше майстерності, і виборці на КППГ часто це цінують.


Боже, яка найвища кількість нам потрібна? Моя поточна спроба не перевищила б, як ... можливо, 20 на TIO.
Чарівний восьминога Урна

@carusocomputing: Довільно високо в теорії , але якщо ви не можете отримати більше 20 в протягом розумного періоду часу на практиці, що це цілком прийнятно.

4
Чи є у вас тестові випадки?
Лука

Я дуже хочу, щоб це була одна операція, поширювана проти кількох змагань. Множення - це проблема ділення, але додавання і додавання і віднімання дійсно ускладнює речі. У мене є рішення, яке працює, але не для додавання і віднімання; зробити цю роботу ідеально буде нудно.
Magic Octopus Urn

@carusocomputing: Тоді вас може зацікавити це завдання . Я підозрюю, що завдання з множенням суттєво відрізняється, і для отримання хорошої оцінки потрібні досить різні методи вирішення.

Відповіді:


1

Python2, 1̶9̶8̶ ̶b̶y̶t̶e̶s̶ 182 байти завдяки 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]

Цей алгоритм не робить нічого, щоб виключити версії префікса +і -, але вони будуть або гіршими, або рівними, і з'являться пізніше в пошуку, їх інфіксні аналоги. Оскільки він використовує аргумент ключового слова eбезперервно, він дасть недійсні результати, якщо викликається кілька разів за сеанс. Щоб виправити це, використовуйте f(n, e=[(0,'')])замість просто f(n). Зауважте, що чотирипроменеві відступи представляють вкладки, тому це буде працювати лише з Python 2.

У мене також є неперероблена та оптимізована версія, яка працює швидко навіть для досить великої кількості:

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)

Деякі неповнолітні гольфи: TIO (182 байт)
математика, наркоман

1

PHP, 241 байт

Інтернет-версія

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

Зламатися

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

Шлях з трохи кращою продуктивністю

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

Підтримка від’ємних цілих чисел

Версія з від'ємними цілими числами

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

О, нескладно, це працює і на від’ємних числах!
Magic Octopus Urn

@carusocomputing насправді не могло бути, що існує рішення з меншими таблицями відповідності, оскільки негативні числа додаються лише відніманням. і в цьому випадку вам слід перевірити абсолютне значення і додати його
Jörg Hülsermann

Я не думаю, що буквальний 333 був би прийнятним тут, хоча ви, швидше за все, могли це виправити, зробивши це деякою функцією вводу. (Програма може працювати набагато повільніше, тому ви можете зберегти

1
@ ais523 done 333 замінено на 2 * введення
Jörg Hülsermann

1
Ви можете індексувати рядки: $e+="6255456376"[$i[$s++]];.
манатура
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.