Розв’яжіть рівняння з (майже) будь-якими числами, які вам подобаються


27

Враховуючи рядок символів, +=-де є хоча б одне =, вставте додатні цілі числа між усіма символами та на початку та в кінці таким чином, щоб математичні рівняння були задоволені.

Наприклад, з урахуванням введення

+-=-=

вам потрібно вставити натуральні цілі від A до F, як це

A+B-C=D-E=F

такі , що рівняння все задоволені, тобто A + B - Cі D - Eі Fвсе той же номер.

Існує багато можливих способів зробити це, оскільки, поки формуються рівняння, може використовуватися будь-який набір натуральних чисел. Кожен рядок тут є можливим дійсним результатом для введення +-=-=:

2+3-4=6-5=1
1+1-1=2-1=1
4+2-4=4-2=2
100+1-10=182-91=91
89+231-77=1024-781=243

Зауважте, що значення виразів не обов'язково, щоб вони були додатними цілими числами, такими як вставлені числа. Наприклад, з урахуванням вхідних даних -=-виходи 1-10=8-17(овалі до -9) та 10-1=17-8(овалі до 9) мають однакову силу. Звичайно, для деяких входів, таких як =неможливо мати від'ємник як вираз, оскільки 5=5можна вставити лише позитивні числа типу .

Зауважте також, що нуль не є додатним цілим числом.

Виграє найкоротший код у байтах.

Ви можете виводити числа як список, а не вставляти їх безпосередньо в рядок. Якщо ви виведете рядок, можуть бути пробіли, що розділяють символи та числа. Отже, для введення +-=-=, виведення

2, 3, 4, 6, 5, 1

або

2 + 3 - 4 = 6 - 5 = 1

еквівалент виводу

2+3-4=6-5=1

Випробування

Input | One Possible Output
= | 1=1
== | 2=2=2
+= | 1+3=4
=+ | 2=1+1
-= | 30-10=20
=- | 1=2-1
=-= | 3=7-4=3
=+= | 2=1+1=2
=== | 100=100=100=100
+=- | 3+2=7-2
-=+ | 7-2=3+2
+=+ | 3+3=3+3
-=- | 1-10=8-17
--= | 60-1-1=58
++= | 60+1+1=62
-+= | 60-9+1=52
+-= | 60+9-1=68
+-=-= | 2+3-4=6-5=1
--=-- | 2-1-1=2-1-1
==-== | 47=47=50-3=47=47
=++=+-=-+=--= | 3=1+1+1=3+1-1=1-1+3=5-1-1=3
+--++-=-+-+- | 35+10-16-29+20+107-1000=5-4+3-2+1-876
====== | 8=8=8=8=8=8=8


Чи можна вважати будь-яку верхню межу довжини формули?
xnor

2
@xnor Ви можете припустити, що введення менше 2 ^ 16 символів, якщо це допомагає.
Захоплення Кальвіна

Відповіді:


16

Сітківка , 58 байт

[-+]
$&1
\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&
+`1_

1+
$.&

Спробуйте в Інтернеті!

Альтернативне рішення з тим самим числом байтів:

((\+)|(-))*
$._$*1$#3$*1$#2$*_$&
+`1_

([+-])1*
$+1
1+
$.&

Спробуйте в Інтернеті!

Пояснення

Основна ідея полягає в тому, щоб перетворити всі +s і -s на прості +1та -1операційні, а потім додати достатньо велике число, яке змушує працювати всі рівняння. Щоб рівняння збігалися, ми можемо просто додати однакове число до кожного з них, а потім зменшити його на одне для кожного +1і збільшити на одне для кожного -1після нього. Оскільки ми будемо працювати з одинарними номерами, єдиний замах - це те, що перше число має бути досить великим, щоб ми могли зменшити його в 1 раз.

[-+]
$&1

Почнемо, вставляючи 1після кожного -або +.

\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&

У \Bгарантує , що ці матчі або на початку введення, або між =і +чи -, тобто всі позиції , де ми хочемо вставити провідне число вираження. Потім ((\+1)|(-1))*частина просто підраховує кількість +1s і -1s у групах 2і 3відповідно. Тепер давайте розбимо рядок заміщення:

$._$*1   # For each character in the current string, insert a 1. This is
         # an offset which is the same for each expression and is guaranteed
         # to be large enough that all subsequent +1s can be cancelled.
$#3$*1   # For each -1, insert a 1.
$#2$*_   # For each +1, insert a _.
$&       # Re-insert the string of +1s and -1s.
+`1_

Неодноразово скидайте 1_з рядка, застосовуючи необхідне скасування від +1s.

1+
$.&

Нарешті, замініть всі рядки 1s на їх довжину, щоб перетворити з унарних в десяткові.


8

Python 2 , 76 байт

lambda e:sum([[len(e+s)-2*s.count('+')]+[1]*len(s)for s in e.split('=')],[])

Спробуйте в Інтернеті!


3
Чи можете ви додати пояснення?
Захоплення Кальвіна

1
@HelkaHomba Ідея досить проста: спочатку візьміть кожен шматок вхідного поділу на рівні знаки. Виберіть перше число кожного фрагмента eqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs. Тоді, оскільки всі інші числа в групі є однакові, загальна кількість шматка працює на eqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_len. Довжина рівняння повинна бути додатною, тому все виходить.
FryAmTheEggman

6

Python 2, 199 179 178 172 162 158 156 152 151 байт

Шлях занадто довгий, але рішення було легко створити.

from itertools import*
i=input()
k='%s'
s=k+k.join(i)+k
for p in product(*[range(1,65537)]*-~len(i)):
    if eval((s%p).replace('=','==')):print s%p;break

Спробуйте в Інтернеті

Це спробує будь-яку можливість, поки не знайде рішення. Програма надзвичайно повільна. Він також виконує заміну рядків кожної ітерації. Редагування "172" зробило це значно повільніше, оскільки замість того, щоб починати з невеликого діапазону, воно починається з максимуму. Наприклад, вхідні дані -=або =+спробувати 2 ** 32 спроби, перш ніж досягти рішення.

Щоб пришвидшити програму, використовуйте версію з 178 байтами з історії редагування.


Чи не rangeв python2 створюється весь діапазон як список відразу? IIRC, ви могли б прискорити його, скориставшись xrangeзамість цього, оскільки я думаю, що це версія для ледачих завантажень (Python3 використовує ледачий за замовчуванням range)
Delioth

1
@Delioth Він використовує інший байт. Мета - видалити байти. Крім того, це насправді не забезпечить значного прискорення, оскільки більшість уповільнень відбувається від кількості ітерацій, а не створення списку, який відбувається лише один раз. Я побіг, print range(1,65537)і це завершилося в 0,034 с.
mbomb007

Ну і, звичайно, більше "це могло б пришвидшити його за точно такою ж методологією", якщо турбуватися про це потрібно так довго. Обмоложення пам'яті може спричинити значне уповільнення. Крім того, ви можете вирізати кілька байтів (можливо, лише 1), не встановивши l=..., а поставивши це право в product(range(...),repeat=len(s)+1). Якщо вам потрібні дужки, це зберігає лише один байт (\ n)
Delioth

@Delioth Навіть якщо мені потрібні паролі навколо len(s)+1, я можу використовувати -~len(s)замість цього, що не вимагатиме паронів.
mbomb007

Ага, правильно. Я завжди забуваю про побитові операції та хитрощі. Це має бути платним, що працює над frontend javascript.
Delioth

5

JavaScript (ES6), 92 82 байт

Гольфував 8 байт з хитрістю від @xnor

let f =
x=>x.split`=`.map(q=>(x+q).length-2*~-q.split`+`.length+[...q,''].join(1)).join`=`
<input oninput="if(/^[+=-]+$/.test(value))O.innerHTML=f(value)" value="="><br>
<pre id=O>1=1</pre>

Хитрість тут полягає в тому, щоб вставити a 1після кожного +або -, а потім до кожного виразу додати число, яке робить вираз рівним довжині вводу. Таким чином ми можемо гарантувати, що кількість завжди є позитивною; оскільки =в рядку завжди є щонайменше 1 , кількість +s ніколи не може досягати довжини рядка, тому залишок завжди принаймні 1. Ви можете перевірити це, ввівши довільну кількість +s у фрагменті вище.


5

Python 2 , 120 119 байт

-1 байт завдяки mbomb007

a=['1'+(n and('1'.join(n)+'1'))for n in input().split('=')]
print'='.join(`max(map(eval,a))-eval(c)+1`+c[1:]for c in a)

Спробуйте в Інтернеті! або Перевірте всі тестові випадки

Спочатку я вставляю 1в кожну позицію, щоб перевірити найвище значення, а потім додаю її як зміщення у кожному рівнянні. Ця робота полягає в тому, що ви не можете додати від'ємні числа, тому мінімальний результат задається кількістю +рівняння, яке є лише +.


Можна видалити пару пробілів.
mbomb007

5

GNU Prolog, 156 байт

x(L,R,V)-->{E#>0},({L=[E|R],E=V};x(L,[E|R],X),("+",{V#=X+E};"-",{V#=X-E})).
q(L,R,V)-->x(L,T,V),({T=R};"=",q(T,R,V)).
s(Q,L):-q(L,[],_,Q,[]),fd_labeling(L).

Пояснення

У нас є купа рівнянь для вирішення, то чому б не використати фактичний розв'язувач рівнянь?

xв основному є оцінювачем рівнянь рівнянь форми +-+; крім самого рівняння, він має два додаткові аргументи (перелік різниць, L,Rщо містять значення рівняння, і значення, Vяке оцінює рівняння). Як зазвичай у Prolog, його можна використовувати в будь-якому напрямку (наприклад, ви можете вказати Vта отримати L,R, вказати L,Rта отримати а V, вказати і те, і перевірити, чи є значення правильним, або вказати ні в якому випадку відповідні обмеження не будуть розміщені як на, так Vі на L,R). "Поточний елемент" L,Rназваний E, і ми також включаємо твердження, щоEбільше 0 (тому що питання вимагає використання додатних чисел). Ця функція трохи більш багатослівна, ніж мені б хотілося, наприклад, мені довелося [E|R]два рази писати відповідність шаблону / невідповідності через те, що списки є право-асоціативними, але додавання та віднімання є ліво-асоціативними. На жаль, нам потрібно використовувати фактичний список, а не придумувати власний тип ліво-асоціативного списку поза клітинами мінусів, fd_labelingщоб працювати.

qподібний x, але також включає =. Це в основному просто дзвінки x, а сама рекурсивно. До речі, це дуже чітка демонстрація того, як працюють різницькі списки, показуючи, що ви можете об'єднати два списки різниць L,Tі T,Rв єдиний різницький список L,R. Основна ідея полягає в тому, що список різниць - це часткова функція, яка бере аргумент Rі повертає значення, Lяке є Rдля нього самим списком. Таким чином, ідентифікуючи аргумент одного списку різниць і повертаючого значення іншого, ми можемо скласти функції і, таким чином, об'єднати списки.

Нарешті, sщо є функціоналом, який фактично вирішує завдання у питанні, це функція обгортки, яка викликає qаргументи. Ми перетворюємо список різниць у звичайний список, подаючи []його аргумент, і використовуємо fd_labelingдля пошуку рішення рівняння, яке ми створили. (За замовчуванням, схоже, встановлення значень до 1, якщо немає причин встановлювати їх на щось інше. Однак, його можна налаштувати; value_method(random)дає більше "цікавих" рішень, ніж ставити 1s скрізь, наприклад, і все ще дуже швидко. )

Вибірка зразка

З написаною програмою:

| ?- s("=++=+-=-+=--=", V).

V = [3,1,1,1,3,1,1,3,1,1,5,1,1,3] ?

Якщо я змушу програму трохи довше додати value_method(random), результат буде різним, але виглядає приблизно так:

| ?- s("=++=+-=-+=--=", V).

V = [68,6,12,50,85,114,131,45,3,26,71,1,2,68] ? 

В обох випадках ?кінець результату означає, що може бути більше одного рішення. (Звичайно, в цьому випадку ми знаємо, що існує багато більше, ніж одне рішення!)


4

Математика, 116 байт

Join@@(Prepend[#^2,1-Min[Tr/@c]+Tr@#]&/@(c=Characters@StringSplit["0"<>#<>"0","="]/."+"->-1/."-"->1/."0"->Nothing))&

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

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1розколе вхідні рядок в кожному знак рівності, а потім замінити кожен +на -1кожен -по 1. Однак якщо на початку чи в кінці є знак рівності, він буде ігнорований. Тому ми штучно додаємо новий символ на кожному кінці ( "0"<>#<>"0") і змушуємо його відходити після завершення розбиття рядків ( /."0"->Nothing).

Загальна кількість кожного підспису тепер дорівнює цілому числу, яке ми можемо поставити перед +s і -s, щоб зробити кожен вираз рівним. 1-Min[Tr/@c]це найменше ціле число, яке ми можемо додати до кожного загального, щоб зробити їх усі позитивними. Таким чином, Prepend[#^2,1-Min[Tr/@c]+Tr@#]&приймає кожен підпис (у ^2свою чергу перетворює всі записи 1) і вважає, що його загальна зміщена на це найменше компенсуюче ціле число. Отримані списки Joinредагуються разом для отримання результату.


3

Рубі, 76

->s{(?1+s.gsub(/./){|a|a+?1}).split(?=).map{|e|e[0]="#{5**8-eval(e)}";e}*?=}

Цільове значення для виразів фіксується на 5**8мінус 1 з міркувань гольфу! Спочатку я використовував s.size+1мінус 1.

Ungolfed в тестовій програмі

f=->s{(?1+s.gsub(/./){|a|a+?1}).           #add a 1 at the beginning and after every symbol
       split(?=).                          #split into an array of expressions at = signs
       map{|e|                             #for each expression string
         e[0]="#{5**8-eval(e)}";e          #change the first number to 5**8-eval(e)
       }*?=                                #and rejoin the strings
}


puts f["="] 
puts f["=="] 
puts f["+="] 
puts f["=+"]
puts f["-="]
puts f["=-"]
puts f["=-="]
puts f["=+="]
puts f["==="]
puts f["+=-"]
puts f["-=+"]
puts f["+=+"]
puts f["-=-"]
puts f["--="]
puts f["++="]
puts f["-+="]
puts f["+-="]
puts f["+-=-="]
puts f["--=--"]
puts f["==-=="]
puts f["=++=+-=-+=--="]
puts f["+--++-=-+-+-"]
puts f["======"]

Вихідні дані

390624=390624
390624=390624=390624
390623+1=390624
390624=390623+1
390625-1=390624
390624=390625-1
390624=390625-1=390624
390624=390623+1=390624
390624=390624=390624=390624
390623+1=390625-1
390625-1=390623+1
390623+1=390623+1
390625-1=390625-1
390626-1-1=390624
390622+1+1=390624
390624-1+1=390624
390624+1-1=390624
390624+1-1=390625-1=390624
390626-1-1=390626-1-1
390624=390624=390625-1=390624=390624
390624=390622+1+1=390624+1-1=390624-1+1=390626-1-1=390624
390624+1-1-1+1+1-1=390625-1+1-1+1-1
390624=390624=390624=390624=390624=390624=390624

2

PHP, 207 204 197 114 байт

прямий підхід: набагато коротший і швидший

foreach(explode("=",$argn)as$t)echo"="[!$c],strlen($argn)+($c=count_chars($t))[45]-$c[43],@chunk_split($t,!!$t,1);

Запустіть echo '<input>' | php -nR '<code>'або випробуйте його в Інтернеті .

зламатися

foreach(explode("=",$argn)as$t) // loop through terms
    echo                            // print ...
        "="[!$c],                       // 1. "=" if not first term
        strlen($argn)                   // 2. maximum number
            +($c=count_chars($t))[45]   //    + number of "-"
            -$c[43],                    //    - number of "+"
        @chunk_split($t,!!$t,1);        // 3. each operator followed by "1"
  • !$cвірно в першій ітерації, 1призначеній для індексування рядків; "="[1]пусто.
    Після цього $cвстановлюється і !$cпомиляється, передається 0і "="[0]є першим символом.
  • Максимальне значення для будь-яких термінів не повинно перевищувати кількість плюсів +1;
    тож ми точно впевнені в довжині вводу. Усі умови будуть оцінюватись відповідно до цього.
  • chunk_split($s,$n,$i)вставляє $iпісля кожного $nсимволу $s- і в кінці.
    Щоб запобігти перетворенню порожніх термінів 1, помилка вимушена, встановивши довжину відрізка до 0.

1

Рода , 112 110 109 байт

f x{[(`:$x:`/"=")()|{|p|p~=":",""a=p;a~=`\+`,""b=p;b~="-","";["=",#x-#b+#a];{(p/"")|{|o|[o,"1"*#o]}_}}_][1:]}

Спробуйте в Інтернеті!

Функція розділення не працювала так, як я задумав у цій програмі. Наприклад, split("", sep="")повертає один порожній рядок замість нічого. Як це логічно? Завдяки цьому програма майже на 20 байт більше, ніж може бути, якби роздільна семантика була ідеальною.

Ідея цієї відповіді полягає в тому, що ми знаємо, що довжина вхідного рядка повинна бути більшою або дорівнює значенню рівняння, тому ми визначаємо значення рівняння як довжину рядка. Для кожної частини рівняння ми думаємо, що кожен оператор будує +1або -1віднімає і додаємо їх до значення рівняння.

Безголівки:

function f(x) {
    /* Adds ":"s around the string to prevent "=" being split wrong. */
    [split(`:$x:`, sep="=") | for p do
        p ~= ":", ""          /* Removes colons. */
        a := p; b := p        /* Initializes a and b to be p. */
        a ~= "\\+", ""        /* The lengths of a and are now equal to the */
        b ~= "-", ""          /* numbers of "-" and "+" characters in x. */
        push("=", #x-#b+#a)   /* Prints "=" and the value of the equation */
                              /* minus number of "+"s plus number of "-"s. */
        split(p, sep="") | for o do /* For each operator: */
            push(o)                 /* Prints the operator. */
            push(1) if [o != ""]    /* Prints 1 unless the operator is "". */
        done
    done][1:] /* Removes the first character of the output ("="). */
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.