Візуалізуйте найбільшого спільного дільника


28

Фон

Найбільший спільний дільник ( gcd для коротких) - це зручна математична функція, оскільки має багато корисних властивостей. Один з них - особа Безута : якщо d = gcd(a, b), значить, існують цілі числа xі yтаке інше d = x*a + y*b. У цьому виклику ваше завдання - візуалізувати цю властивість за допомогою простого мистецтва ASCII.

Вхідні дані

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

Вихідні дані

Вихід - це рядок sдовжини lcm(a, b) + 1( lcm означає найменший загальний кратний). Символи sпредставляють цілі числа від 0до lcm(a, b). Символ s[i]- це малий регістр, oякщо iкратний aабо b, а період - .інакше. Зауважте, що нуль кратний кожному числу. Тепер через особу Безута залишиться щонайменше одна пара персонажів, oна sвідстані якої саме така gcd(a, b). Найменшу ліву таку пару слід замінити великими літерами Os; це кінцевий результат.

Приклад

Розглянемо вхідні дані a = 4та b = 6. Тоді ми маємо gcd(a, b) = 2і lcm(a, b) = 12, тому довжина sбуде 13. Множини aта bвиділяються наступним чином:

0  1  2  3  4  5  6  7  8  9 10 11 12
o  .  .  .  o  .  o  .  o  .  .  .  o

Є дві пари os з відстані два, але ми замінимо лише самі ліві ліві на Os, тому кінцевий вихід є

o...O.O.o...o

Правила та оцінка

Ви можете написати повну програму або функцію. Виграє найменший кількість байтів, а стандартні лазівки заборонені.

Тестові справи

 1  1 -> OO
 2  2 -> O.O
 1  3 -> OOoo
 4  1 -> OOooo
 2  6 -> O.O.o.o
 2  3 -> o.OOo.o
10  2 -> O.O.o.o.o.o
 4  5 -> o...OO..o.o.o..oo...o
 8  6 -> o.....O.O...o...o.o.....o
12 15 -> o...........O..O........o.....o.....o........o..o...........o
19 15 -> o..............o...o..........o.......o......o...........o..o..............OO.............o....o.........o........o.....o............o.o..............o.o............o.....o........o.........o....o.............oo..............o..o...........o......o.......o..........o...o..............o

1
Чи можемо взяти одинарне введення, чи можемо ми вибрати будь-якого символу? (Зокрема, як щодо ., oабо O.) Або це має бути 1? Або 0?
Мартін Ендер

1
@ MartinBüttner Це може бути будь-який символ, якщо ви послідовні та використовуєте однаковий формат для обох входів.
Згарб

2
Я здивований, що ви не використовували 3 та 5 як один із своїх тестових випадків.
Ніл

Чи можна використовувати buildin?
Акангка

@ChristianIrwan Так, всі вбудовані модулі дозволені.
Згарб

Відповіді:


7

Джольф, 52 байти

on*'.wm9jJΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n

Я розділю цей код на дві частини.

on*'.wm9jJ
on         set n
  *'.       to a dot repeated
      m9jJ  the gcd of two numeric inputs

ΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n
    *Y                                    multiply (repeat) Y (Y = [])
      hm8jJ                                by the lcm of two inputs + 1
  _m       DN              }              and map the array of that length
             ?<*%Sj%SJ1'o'.               "choose o if i%a*(i%b)<1; otherwise choose ."
 R                          "'            join by empty string
Ρ                            'o%o"n        replace once (capital Rho, 2 bytes): "o"+n+"o"
                                   "O%O"n   with "O"+n+"O"
                                          implicit printing

Спробуйте тут!


Коротше, ніж усе інше досі. : P
Rɪᴋᴇʀ

1
@RikerW Так! Я сподіваюся, що Йолф нарешті колись переможе.
Conor O'Brien

10

Джулія, 111 110 107 103 96 байт

f(a,b)=replace(join([i%a*(i%b)<1?"o":"."for i=0:lcm(a,b)]),"o$(d="."^(gcd(a,b)-1))o","O$(d)O",1)

Це функція, яка приймає два цілих числа і повертає рядок.

Безголівки:

function f(a::Int, b::Int)
    # Construct an array of dots and o's
    x = [i % a * (i % b) < 1 ? "o" : "." for i = 0:lcm(a, b)]

    # Join it into a string
    j = join(x)

    # Replace the first pair with distance gcd(a, b) - 1
    replace(j, "o$(d = "."^(gcd(a, b) - 1))o", "O$(d)O", 1) 
end

Збережено байт завдяки німі!


10

Сітківка , 112 109 99 94 91 байт

^
. 
+r`(?<!^\1+). (.+) 
$'$0
.(?=.* (.+) (.+))(?=\1* |\2* )
o
o(\.*)o((\1\.*o)*) .*
O$1O$2

Думаю, не дуже конкурентоспроможний, але теорія чисел у Retina - це завжди дуже цікаво. :)

Приймає введення як одинарні числа, використовуючи .як одинарну цифру.

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

Пояснення

^
. 

Тут вставляється a .та пробіл перед входом. Це в кінцевому підсумку стане результатом.

+r`(?<!^\1+). (.+) 
$'$0

Це додає LCM до aта bрядка. Оскільки ми вже маємо .там, ми закінчимо lcm(a,b)+1. Це досягається багаторазовим наперед b, доки aцей розділ не розділиться. Ми беремо aв групу один і потім перевіряємо, чи зможемо ми дійти до початку рядка, порівнюючи це захоплення хоча б один раз. bПотім вставляється в рядок через рідко використовуваний, $'який вставляє все після матчу в заміну.

.(?=.* (.+) (.+))(?=\1* |\2* )
o

Цей параметр відповідає символам у позиціях, розділених на aабо b. Він використовує той факт, що результат є симетричним: оскільки lcm(a,b)ділиться на обидва aі bйде вліво, віднімаючи екземпляри aабо отримує bту саму схему, що йшла праворуч 0, додаючи їх. Перший лукахед просто захоплює aі b. Другий підказок перевіряє, чи є кратне число кожного aабо bсимволів перед першим пробілом.

o(\.*)o((\1\.*o)*) .*
O$1O$2

Як зазначається у Вікіпедії, окрім особи Безута, це також правда

Найбільший спільний дільник d- найменше додатне ціле число, яке можна записати як ax + by.

Це означає, що GCD відповідатиме найкоротшому розриву між двома os у виході. Тож нам взагалі не потрібно заважати знаходити GCD. Натомість ми просто шукаємо перший екземпляр найкоротшого розриву. o(\.*)oвідповідає розриву кандидата і фіксує його ширину в групу 1. Потім ми намагаємося досягти першого пробілу, чергуючи зворотні відношення до груп 1 і os (з додатковими додатковими .s). Якщо в правій частині буде коротший проміжок, цей збіг не збігається, оскільки ми не можемо пройти цей проміжок із зворотною референцією. Як тільки всі подальші прогалини стануть як мінімум такими ж, як і нинішні, це збігається. Ми фіксуємо кінець LCM-рядка в групу 2 і співставляємо решту рядка з .*. Ми списуємо великі регістриOs (з проміжком між ними), а також залишок рядка LCM, але відкиньте все, починаючи з пробілу, для видалення aта bостаточного результату.


Я мало знаю про теорію чисел Retina, але чи не встановив би вхідний символ на щось, що не вимагає уникнути збереження байтів? Тобто (\.*)=>(a*)
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Так, але тоді мені доведеться замінити його на .пізніший, який коштує чотири байти (а позбавлення від втечі лише економить 3).
Мартін Ендер

Ох. Класно! Дуже цікава відповідь.
Conor O'Brien

5

𝔼𝕊𝕄𝕚𝕟, 50 символів / 90 байт

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

Try it here (Firefox only).

Повинен бути спосіб гольфу далі!

Пояснення

Це основний двофазний алгоритм. Насправді це досить просто.

Фаза 1

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝

Спочатку ми створюємо діапазон від 0 до LCM + 1. Потім ми відображаємо його, перевіряючи, чи один із входів є фактором поточного елемента в діапазоні. Якщо так, ми замінюємо цей елемент на o; в іншому випадку ми замінюємо його на .. Приєднавшись до цього, ми надаємо низку точок, і ми можемо перейти до другої фази.

2 фаза

ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

Це лише одна велика функція заміни. Регекс створюється як o[dots]o, де кількість крапок визначається GCD-1. Оскільки цей регулярний вираз не є глобальним, він відповідатиме лише першому виникненню. Після цього збіг замінюється за O[dots]Oдопомогою функції toUpperCase.


3

MATL , 72 байти

Використовується версія 6.0.0 , яка є раніше, ніж ця проблема. Код працює в Matlab і в Octave.

2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)

Приклад

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 1
> 1
OO

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 2
> 3
o.OOo.o

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 12
> 15
o...........O..O........o.....o.....o........o..o...........o

Пояснення

Я поняття не маю, як це працює. Я просто набрав символів випадковим чином. Я думаю, що тут є якась згортка.

Редагувати: Спробуйте в Інтернеті! Код у посиланні було дещо змінено, щоб відповідати змінам мови (станом на 2 червня 2016 р.).


Не можна вводити 72-байтну програму випадковим чином. Імовірність обчислять пізніше (після сну та деякого часу)
CalculatorFeline

2

Japt , 83 байти

'.pD=U*V/(C=(G=@Y?G$($YX%Y :X} $($UV)+1 £Y%U©Y%V?".:o"} $.replace($E=`o{'.pC-1}o`Eu

Ще не повністю гольф ... І не хоче бути в гольфі: /


Не можете використовувати rзамість $.replace($?
ETHproductions

@Eth я не придумав, як замінити без прапора g, так ні, не можу.
nicael

2

Javascript, 170 164 161 153 145 141 136 байт

(a,b)=>[...Array(a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b))+1)].map((x,i)=>i%a&&i%b?'.':'o').join``.replace(`o${e='.'.repeat(c-1)}o`,`O${e}O`)

Це зовсім lonnnggggg ....

Демо , чітко визначені змінні, оскільки інтерпретатор використовує суворий режим.


Спробуйте замінити i%a<1||i%b<1?'o':'.'наi%a&&i%b?'.':'o'
Mama Fun Roll

О так, я думаю, ви можете псевдоніми приєднатися.
Mama Fun Roll

@ ן nɟuɐɯɹɐ ן oɯ дякую, також замінюючи масиви простим повторенням.
nicael

О, тоді в цьому випадку ви, мабуть, не повинні приєднуватися до псевдоніму, якщо у вас не буде 3 випадків.
Mama Fun Roll

[...Array((d=a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b)))+1).keys()].map(i=>i%a&&i%b?'.':'o')економить два байти. (Я також намагався використовувати індексацію рядків для створення "." Та "o", але це фактично коштує два байти.)
Ніл

1

Python 2, 217 200 191 байт

Це трохи тупо, але це працює. Будь-які поради з гольфу цінуються, особливо якщо ви знаєте, як виправити цю s[i] = s[v] = "o"проблему, з якою я зіткнувся, де це перезаписало б "O" s Зрозуміло!

g=lambda a,b:b and g(b,a%b)or a
def f(a,b):
 h=g(a,b);x=1+a*b/h;s=["."]*x;v=k=0
 for i in range(x):
    if(i%a)*(i%b)<1:
     if k:s[i]="o"
     else:k=i==h+v;s[i]=s[v]="oO"[k]
     v=i
 return''.join(s)

Безголівки:

def gcd(a,b):                           # recursive gcd function
    if b:
        return g(b,a%b)
    else:
        return a
def f(a,b):
    h = gcd(a,b)
    x = 1 + a*b/h                       # 1 + lcm(a,b)
    s = ["."] * x
    v = 0
    k = 0
    for i in range(x):
        if i%a == 0 and i % b == 0:
            if k == 0:
                k = (i == h+v)          # correct distance apart?
                if k:                   # if "O" just found
                    s[i] = s[v] = "O"
                else:
                    s[i] = s[v] = "o"
            else:
                s[i] = "o"              # if "O" already found, always "o"
            v = i                       # If we found an "o" or an "O", i is the new v
    return ''.join(s)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.