최대 공약수를 시각화합니다


28

배경

가장 큰 공약수 ( 간단히 gcd )는 유용한 속성이 많기 때문에 편리한 수학적 함수입니다. 그 중 하나는 베주 항등식 : 경우 d = gcd(a, b), 다음 정수가 존재 xy그러한가 d = x*a + y*b. 이 과제에서 간단한 ASCII 아트를 사용하여이 속성을 시각화해야합니다.

입력

입력 값은 양의 정수 2 개 a이며 b합리적인 형식으로 제공됩니다. 단항 입력 (선택한 단일 인쇄 가능 ASCII 문자 반복)을 사용할 수도 있지만 일관되고 두 입력에 동일한 형식을 사용해야합니다. 입력은 임의의 순서 일 수 있으며, 동일 할 수 있습니다.

산출

출력은 s길이 의 문자열 입니다 lcm(a, b) + 1( lcm 은 최소 공배수를 나타냄). 의 문자는 s에서 0까지의 정수를 나타냅니다 lcm(a, b). 또는 의 배수 인 경우 문자 s[i]는 소문자 o이고 그렇지 않은 경우 마침표 입니다. 0은 모든 숫자의 배수입니다. 이제 베주 항등식의 때문에, 문자의 적어도 한 쌍의가있을 것 에서 거리가 정확하게 누구 . 가장 왼쪽 쌍은 대문자로 대체됩니다 . 이것이 최종 출력입니다.iab.osgcd(a, b)O

입력 a = 4과를 고려하십시오 b = 6. 그럼 우리가 가지고 gcd(a, b) = 2lcm(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

o거리 가 2 인 두 쌍의 s가 있지만 가장 왼쪽의 쌍만 s로 바꾸 O므로 최종 출력은 다음과 같습니다.

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?
Martin Ender 2016 년

1
@ MartinBüttner 일관되고 두 입력에 동일한 형식을 사용하는 한 모든 문자가 될 수 있습니다.
Zgarb

2
테스트 사례 중 하나로 3과 5를 사용하지 않은 것에 놀랐습니다.
Neil

빌드 인을 사용할 수 있습니까?
Akangka

@ChristianIrwan 예, 모든 내장 기능이 허용됩니다.
Zgarb

답변:


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 네! Jolf가 마침내 한 번 승리하기를 바라고 있습니다.
코너 오브라이언

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

nimi 덕분에 바이트를 절약했습니다!


10

망막 , 112 (109) 99 94 91 바이트

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

경쟁이 심하지는 않지만 레티 나의 수 이론은 항상 재미 있습니다. :)

단항 숫자를 사용하여 단항 숫자로 입력을 .받습니다.

온라인으로 사용해보십시오.

설명

^
. 

.입력 앞에 a 와 공백 이 삽입됩니다 . 이것은 궁극적으로 출력이 될 것입니다.

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

이것은의 LCM 앞에 추가 ab문자열을. 우리는 이미 .거기에 있기 때문에로 끝날 것입니다 lcm(a,b)+1. 이것은 반복적 앞에 추가하여 수행 b한 것처럼 a이 새로운 접두사를 분할하지 않습니다. a그룹 1로 캡처 한 다음 캡처를 한 번 이상 일치시켜 문자열의 시작 부분에 도달 할 수 있는지 확인합니다. b다음 드물게 사용을 통해 문자열에 삽입되는 $'삽입 모든 대체에 일치합니다.

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

이것은 하나에 의해 분할 위치에 문자와 일치 a또는 b. 이 결과가 대칭이라는 사실을 이용한다 : 때문에 lcm(a,b)양쪽으로 나누어 ab인스턴스 감산 남긴 것 a또는 b수확량에서 오른쪽으로 가고 동일한 패턴 0에 추가하여이. 첫 번째 예견은 단순히 a및을 캡처합니다 b. 두 번째 lookahead는 첫 번째 공백 앞에 여러 문자 a또는 b문자 가 있는지 확인합니다 .

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

Wikipedia에 명시된 바와 같이 Bézout의 정체성뿐만 아니라

최대 공약수 d는로 쓸 수있는 가장 작은 양의 정수입니다 ax + by.

이것은 GCD가 o출력에서 두 s 사이의 가장 짧은 간격에 해당함을 의미합니다 . 따라서 우리는 GCD를 찾는 것을 귀찮게 할 필요가 없습니다. 대신 가장 짧은 간격의 첫 번째 인스턴스 만 찾습니다. o(\.*)o후보 간격과 일치하고 너비를 그룹 1로 캡처합니다. 그런 다음 그룹 1과 os에 대한 역 참조 (선택 사항 인 추가 .s) 를 번갈아 가며 첫 번째 공간에 도달하려고합니다 . 오른쪽으로 더 짧은 간격이 있으면 역 참조로 해당 간격을 지나갈 수 없기 때문에 일치하지 않습니다. 모든 추가 간격이 최소한 현재 간격만큼 넓어지면 일치합니다. LCM 문자열의 끝을 그룹 2로 캡처하고 나머지 문자열을와 일치시킵니다 .*. 대문자를 다시 쓴다O나머지 LCM 문자열뿐만 아니라 s (사이에 공백이 있음)가 있지만 공간에서 시작하여 제거 a하고 b최종 결과에서 모든 것을 버립니다 .


Retina 숫자 이론에 대해서는 잘 모르지만 입력 문자를 이스케이프 저장 바이트가 필요없는 것으로 설정하지 않습니까? 즉 (\.*)=>(a*)
코너 오브라이언

@ CᴏɴᴏʀO'Bʀɪᴇɴ 네,하지만 .나중에 그것을 4 바이트로 바꾸어야 합니다 (이스케이프를 제거하는 것은 3을 절약합니다).
Martin Ender

오 시원한! 매우 흥미로운 답변입니다.
코너 오브라이언

5

𝔼𝕊𝕄𝕚𝕟, 50 자 / 90 바이트

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

Try it here (Firefox only).

더 골프를 치는 방법이 있어야합니다!

설명

이것은 기본적인 2 단계 알고리즘입니다. 실제로는 매우 간단합니다.

1 단계

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

먼저 0에서 LCM + 1 사이의 범위를 만듭니다. 그런 다음 입력 중 하나가 범위의 현재 항목의 요인인지 확인하여 매핑합니다. 그렇다면 해당 항목을 o; 그렇지 않으면이를로 대체합니다 .. 합치면 2 단계로 넘어갈 수있는 일련의 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

설명

나는 그것이 어떻게 작동하는지 전혀 모른다 . 방금 문자를 무작위로 입력했습니다. 컨볼 루션이 관련되어 있다고 생각합니다.

편집 : 온라인으로 사용해보십시오! 링크의 코드는 언어 변경 사항에 맞게 약간 수정되었습니다 (2016 년 6 월 2 일 기준).


72 바이트 프로그램을 임의로 입력 할 수 없습니다. 나중에 확률을 계산합니다 (잠자는 동안 잠시 동안 활동 한 후)
CalculatorFeline

2

apt , 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

자바 스크립트, 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입니다 ....

인터프리터가 엄격 모드를 사용하므로 Demo , 명시 적으로 정의 된 변수


교체 시도 i%a<1||i%b<1?'o':'.'i%a&&i%b?'.':'o'
엄마 재미 롤

네, 별칭 가입이 가능하다고 생각합니다.
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')2 바이트를 절약합니다. (또한 문자열 인덱싱을 사용하여 '.'및 'o'를 만들려고했지만 실제로 2 바이트가 소요됩니다.
Neil

1

파이썬 2, 217 200 191 바이트

이것은 약간 둔하지만, 작동합니다. 골프 관련 팁, 특히 s[i] = s[v] = "o"내가 겪은 문제 를 해결하는 방법을 알고 있다면 "O"를 덮어 쓸 수 있습니다.

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.