미적으로 유쾌한 제수 트리 만들기


43

미적으로 유쾌한 제수 트리는 n모든 합성 수 에 대해의 제곱근에 가장 가까운 제수 쌍인m 두 개의 자식 노드를 갖는 입력 제수 트리 입니다 . 왼쪽 노드는 더 작은 제수 여야하고 오른쪽 노드는 더 큰 제수 여야합니다 . 트리의 소수에는 자식 노드가 없어야합니다. 당신의 나무는 텍스트 아트 또는 이미지 형태 일 수 있습니다. 텍스트 아트 출력 규칙은 다음과 같습니다.mmm

간격 규칙

트리에서 노드 간격을두기 위해 다음 규칙이 있습니다.

  • 루트에서 지정된 깊이의 노드는 모두 출력에서 ​​동일한 텍스트 줄에 있어야합니다.
  / \ NOT / \  
 / \ / 삼
2 3 2
  • 왼쪽 노드의 경우, 노드가 한 자리 숫자 인 경우에는 수신 분기가 오른쪽 상단에 있어야합니다. 그렇지 않으면 마지막 자리 바로 위에 있습니다. 예:
 / 그리고 /
3720
  • 오른쪽 노드의 경우 노드가 한 자리 숫자 인 경우 들어오는 분기는 왼쪽 상단에 있어야합니다. 그렇지 않으면 첫 번째 숫자 바로 위에 있습니다. 예:
그리고 \
 7 243
  • 나가는 왼쪽 분기의 경우 분기는 숫자 왼쪽에서 한 칸씩 시작해야합니다. 예:
  275
 /
11
  • 나가는 오른쪽 분기의 경우 분기 오른쪽에서 한 칸씩 시작해야합니다. 예:
275
   \
   25
  • 같은 레벨의 트리에있는 두 노드는 그들 사이에 최소 두 개의 공백이 있어야합니다. 동시에, 동일한 레벨의 트리 에 있는 두 개의 서브 트리는 가능한 한 적은 간격을 가져야합니다.
** 하위 트리 **가 너무 가까워서이 트리가 작동하지 않습니다.

        504           
       / \          
      / \         
     / \        
    / \       
   21. 24     
  / \. / \    
 / \. / \   
3 7. 4 6  
        . / \ / \
        .2 2 2 3

이 나무는 가지 사이에 충분한 공간이 있습니다.

         504           
        / \          
       / \         
      / \        
     / \       
    / \      
   21 ... 24     
  / \ ... / \    
 / \ ... / \   
3 7 ... 4 6  
        ... / \ / \ 
        ... 2 2 3
  • 두 개의 하위 트리가 나무에서 너무 가까이 있으면 /\부모 위의 트리에 다른 분기 행을 추가하여 분리 할 수 ​​있습니다 .
   441                              
  / \ 마지막 행이 아직 채워지지 않았으며 이미 공간이 부족합니다.
 21 21
/ \ / \

분기의 다른 행 추가

     441                              
    / \ 거의 비슷하지만 7과 3이 너무 가깝습니다.
   / \ 하나 더 행해야합니다.
  21 21
 / \ / \
3 7 3 7

분기의 다른 행 추가

      441
     / \ 끝났습니다.
    / \
   / \
  21 21
 / \ / \
3 7 3 7

전체 예를 들어, 24의 제수 트리는 다음과 같습니다.

     24
    /  \
   /    \
  4      6
 / \    / \
2   2  2   3

4와 6은 24의 제곱근에 가장 가까운 한 쌍의 제수입니다. 4는 더 작기 때문에 왼쪽에 있습니다. 다음 줄에서 3의 왼쪽에있는 숫자 2는 더 작기 때문입니다.

63의 제수 트리는 다음과 같아야합니다.

  63        and NOT like this        63
 /  \                               /  \
7    9                             3   21
    / \                               /  \
   3   3                             7    3

잘못된 트리에서 3과 21은 63의 제곱근에 가장 가까운 제수 쌍이 아니며 3과 7은 올바르게 정렬되지 않습니다. 그러나 21의 지점 배치는 정확합니다.

42의 경우 다음이 있어야합니다.

    42      and NOT        42
   /  \                   /  \
  6    7                 21   2
 / \                    /  \
2   3                  3    7

720을 보도록하겠습니다 720. 24그리고 30하위 트리가 올바르게 배치 되도록 5 가지 레벨의 분기가 필요 합니다. 또한, 참고 2430지점의 두 가지 수준을 가지고 있기 때문에 4하고 6정확한 간격과의 아이 노드가 필요 아이 노드가 30의 아이 노드와 동일한 수준에있을 필요 24.

           720
          /   \
         /     \
        /       \
       /         \
      /           \ 
     24           30
    /  \         /  \
   /    \       /    \
  4      6     5      6
 / \    / \          / \
2   2  2   3        2   3

도전

  • 당신의 임무는 입력을 위해 올바르게 배치 된 미적으로 유쾌한 제수 트리를 만드는 것입니다. n여기서 n1보다 큰 양의 정수입니다.
  • 출력에는 선행 및 후행 공백과 선행 및 후행 줄 바꿈이 포함될 수 있지만 위에 제공된 간격 규칙을 준수해야합니다.
  • 텍스트 아트, 이미지 (필요한 경우 추가 할 다른 형식)로 출력 할 수 있습니다.
  • 이미지의 경우 트리의 노드 간격이 일정하고 트리에서 동일한 높이의 노드가 이미지에서 동일한 높이인지 확인하십시오.
  • 이것은 코드 골프입니다. 최소 바이트 수 (또는 이에 상응하는)가 이깁니다.

이 아이디어를 생각한 Stewie Griffin에게 감사의 말을 전하며 사양을 다시 작성하는 데 도움을 준 Peter Taylor, Martin Ender, Mego 및 Eᴀsᴛᴇʀʟʏ Iʀᴋ에게 감사의 말을 전합니다. 평소와 같이 제안이나 수정은 대단히 감사하겠습니다. 행운과 좋은 골프!

더 많은 테스트 사례 :

2

  4
 / \
2   2

    20
   /  \
  4    5
 / \
2   2

  323
 /   \
17   19

                        362880
                       /      \
                      /        \
                     /          \
                    /            \
                   /              \
                  /                \
                 /                  \
                /                    \
               /                      \
              /                        \
            576                        630
           /   \                      /   \
          /     \                    /     \
         /       \                  /       \
        /         \                /         \
       /           \              /           \
      /             \            /             \
     24             24          21             30
    /  \           /  \        /  \           /  \
   /    \         /    \      /    \         /    \
  4      6       4      6    3      7       5      6
 / \    / \     / \    / \                        / \
2   2  2   3   2   2  2   3                      2   3

              1286250
             /       \
            /         \
           /           \
          /             \
         /               \
      1050               1225
     /    \             /    \
    /      \           /      \
   /        \         /        \
  30        35       35        35
 /  \      /  \     /  \      /  \
5    6    5    7   5    7    5    7
    / \
   2   3

이 도전에 감사합니다. 매번 그림을 그릴 필요없이 이러한 것들을 시각화 할 수 있습니다. D
Conor O'Brien

트리가 예제처럼 보이거나 내장 Mathematica 함수를 사용할 수 있습니까? 그것은 모양 인수 분해와 함께하지만,.
JungHwan Min

@ JHM 그래픽 출력 태그를 유지해야한다는 것을 알고있었습니다 . 예, 기본 제공 기능을 사용할 수 있습니다. 도전을 편집하겠습니다.
Sherlock9

답변:


29

파이썬 (2) , 711 (651) 575 559 554 547 539 540 530 522 바이트

이 답변을 쓰려고 노력한 지 4 개월이 지난 후, 벽에 뛰어 들어 1 주일 동안 그대로 두었다가 헹구고 반복 한 후에 마침내이 과제에 대한 적절한 ASCII 아트 답변을 마쳤습니다. 남은 것은 골프뿐이므로 골프 제안은 매우 환영합니다. 온라인으로 사용해보십시오!

골프 : 자주 사용되는 일부 함수의 이름을 바꾸고 결과가 반환되는 방식을 변경하여 -60 바이트. 하위 트리의 높이 확인 방법, 간격 변수 계산 방법 및 결과 반환 방법을 변경하는 -73 바이트 FlipTack isdigit()대체 에서 -3 바이트 -16 바이트가 골프를 isdigit()대체하고 ""를으로 대체 E합니다. 사소한 개선에서 -5 바이트 및 Python 3에서 Python 2로 변경 -7 바이트는 결과 리턴 방법 수정에서. 작은 변경에서 A정의 된 방법으로 -8 바이트 , 정의 된 방법 변경 TW대응하는 것보다 적어도 하나의 더 긴 분기를 가진 서브 트리가 대응 하는 것보다 전체적으로 더 길다는 가설을 사용하여 추가Q결과가 어떻게 반환되는지 편집하십시오. for 및 A<10대신에 -10 바이트 사용 . -8 바이트는 기본값 을 변경 하지 않기 때문에 코드는 절대 변경하지 않고 변경 하는 기본 인수의 문제를 피하고 대신에 를 사용하여 정의 방법을 변경 하고 전체를 제거 하고에 대한 대체물로 작성 하여 변경합니다 .L(S(A))<2ABH[0]Hq(B>9)1-(B<10)pFp+q-M

버그 수정 : 가설이 잘못되었습니다 11**9 = 2357947691. +1 바이트

G=range;L=len;E=" "
def t(n,H=[0]):
 A=max(z*(n%z<1)for z in G(1,int(n**.5)+1));B=n/A;Z=str(n);M=L(Z)
 if A<2:return[Z]
 T=max([i for i in G(L(w))if"/"not in w[i]]for w in(t(A),t(B)));V=H[1:]or[T[k+1]-T[k]-1for k in G(L(T)-1)];x=t(A,V);y=t(B,V);P=x[0].rindex(str(A)[-1])+(A<10);q=y[0].index(str(B)[0])+(B>9);F=L(x[0])-P+q-M;h=H[0]or(F+M%2+2)/2or 1;return[E*(P+J)+(J<h and"/"+E*(2*h+M-2*J-2)+"\\"or Z)+E*(L(y[0])-q+J)for J in G(h,-1,-1)]+[(E*(2*h-F)).join(I<L(w)and w[I]or E*L(w[0])for w in(x,y))for I in G(max(L(x),L(y)))]

설명

전체 기능을 약 4 단계로 끓일 수 있습니다.

  1. 의 가장 큰 제수 쌍을 결정 n, A하고 B.
  2. A및 의 하위 트리를 만들고 B필요에 따라 다시 그립니다.
  3. 서브 트리 사이에 있어야 할 공간 수를 결정하십시오.
  4. 새로운 제수 트리를 그리고 돌려줍니다.

각 단계를 순서대로 진행하겠습니다.

1 단계. 이것은 가장 솔직한 단계입니다. 모든 번호 확인 z(1) 사이에 가분성에 대한 제곱근을 n가장 큰 잡아 zn//z그 일치를. 소수 ( 또는 ) 인 str(n)경우에만 반환nA==1B==n

단계 2. 하위 트리를 A그리고 하위 트리에서 노드 사이 B/\분기 수를 가져옵니다 . 이를 위해 우리는 숫자가있는 모든 단계의 인덱스를 얻고 인덱스의 첫 번째 차이를 얻은 다음 1을 다시 뺍니다. 높이가 확보되면 높이를 비교하여 가장 큰 값을 얻고 하위 트리를 새 높이로 다시 그립니다.

나는 전체적으로 더 큰 하위 트리가 항상 더 짧은 하위 트리의 분기만큼 길거나 같은 분기를 가지고 있다는 몰래 의심을 가지고 있으며, 이것을 사용하여 코드를 골프화 할 수는 있지만 아직 이에 대한 증거는 없습니다. 의 반례 11**9 = 2357947691.

3 단계. 이 단계는 몇 달이 걸렸습니다. 2 단계는 작성하고 디버깅하는 데 며칠이 걸렸지 만 간격에 적합한 수식을 찾는 데는 오랜 시간이 걸렸습니다. 내가 알아 낸 것을 몇 개의 문단으로 요약 할 수 있는지 살펴 보겠습니다. 이 설명의 코드 중 일부는 실제 코드에서 제외되었습니다.

첫째, p, q, h, P, Q, sM. p왼쪽 분기 /의 끝에서 왼쪽 하위 트리의 오른쪽 끝까지의 문자 수입니다 . q오른쪽 하위 트리의 왼쪽 끝에서 오른쪽 분기의 끝까지의 문자 수입니다 /. h루트와 하위 트리 사이의 분기 수입니다. P그리고 Q단지 역원은 pq주변 공간 배치에 유용 /\루트까지 가지 n. s두 하위 트리 사이에 추가되는 공백 수입니다. M가장 간단합니다. 의 길이입니다 n. 그래픽으로 표현 :

            M
           ---
           720           
 |        /   \          
 |       /     \         
h|      /       \        
 |     /         \       
 |    /           \      
   P    p    s   q   Q   
------______---____------
     24           30     
    /  \         /  \    
   /    \       /    \   
  4      6     5      6  
 / \    / \          / \ 
2   2  2   3        2   3

결정 공식은 다음 p과 같습니다. p = len(x[0]) - x[0].rindex(str(A)[-1]) - (A<10), 길이, A에서 마지막 문자의 0 인덱스 빼기-한 자릿수에 대한 수정 빼기 A.

결정의 공식은 다음 q과 같습니다. q = y[0].index(str(B)[0]) + (B>9), B의 첫 번째 문자의 색인과 0 인덱싱에 대한 수정에서 한 자릿수에 대한 수정을 뺀 값 B(여러 자릿수에 대한 하나의 수정으로 결합 B).

결정 공식 h은 다음과 같습니다 h = H[0] or (p+q+M%2+2-M)//2 or 1.. 사전 정의에서 H가져와 트리를 다시 작성하거나을 사용 (from_the_left + from_the_right + parity_space + 2 - len(root)) // 2)하거나 최소 분기 레벨 수인 1을 사용함을 의미합니다.

결정 공식 s은 다음과 같습니다 s = 2*h+M-p-q.. 우리는 빼기 pq그 넓은에서 루트의 나뭇 가지 사이에 공간의 수에서 2*h + M.

4 단계. 그리고 마지막으로 우리는 그것을 모두 모았습니다. 먼저 루트를 [" "*(P+h)+Z+" "*(Q+h)]만든 다음 분기를 하위 트리로 내려간 다음 [" "*(P+J)+"/"+" "*(2*h+M-2*J-2)+"\\"+" "*(Q+J)for J in G(h)][::-1]마침내 적절한 간격의 하위 트리를 넣습니다 [(" "*(2*h+M-p-q)).join([(I<L(w)and w[I]or" "*L(w[0]))for w in(x,y)])for I in G(max(L(x),L(y)))].

vo! 우리에게는 미적으로 유쾌한 제수 나무가 있습니다!

풀기 :

def tree(n, H=[0]):
    A = max(z for z in range(1, int(n**.5)+1) if n%z<1)
    B = n/A
    Z = str(n)
    M = len(Z)
    if A < 2:
        return [Z]

    # redraw the tree so that all of the numbers are on the same rows
    x = tree(A)
    y = tree(B)
    for W in [x, y]:
        T = [i for i in range(len(W)) if "/" not in W[i]]
    V = H[1:] or [T[k+1]-T[k]-1 for k in range(len(T)-1)]
    x = tree(A, V)
    y = tree(B, V)

    # get the height of the root from the two trees
    P = x[0].rindex(str(A)[-1]) + (A < 10)
    p = len(x[0]) - P
    q = y[0].index(str(B)[0]) + (B > 9)
    Q = len(y[0]) - q
    h = hs[0] or (p+q+M%2+2-M)/2 or 1

    # and now to put the root down
    R = []
    s = 2*h+M-p-q
    for I in range(max(len(x),len(y))):
        c = I<len(x) and x[I] or " "*len(x[0])
        d = I<len(y) and y[I] or " "*len(y[0])
        R += c + " "*s + d,
    for J in range(h, -1, -1):
        if J<h:
            C = "/" + " "*(2*h+M-2*J-2) + "\\"
        else:
            C = Z
        R += [" "*(P+J) + C + " "*(Q+J)]
    return R

당신의 수 isdigit검사는 수 '/'<x[i].strip()[0]<':'?
FlipTack

14

매스 매 티카, 96 86 81 79 78 바이트

2 바이트에 대한 @MartinEnder에게 감사합니다.

TreeForm[If[PrimeQ@#,#,#0/@(#2[#,#2/#]&[Max@Nearest[Divisors@#,#^.5],#])]&@#]&

결과는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

설명

Max@Nearest[Divisors@#,#^.5]

입력의 제수 목록을 생성하십시오. 입력의 제곱근에 가장 가까운 요소를 찾으십시오. ( Max출력을 평탄화하기위한 것입니다)

#2[#,#2/#]&

위에서 찾은 제수로 입력을 나누어 다른 제수를 찾아서 결과를 헤드로 적용하십시오.

#0/@

과정을 반복하십시오.

If[PrimeQ@#,#, ... ]

입력 값이 소수이면 아무 것도하지 마십시오.

TreeForm

출력을 포맷하십시오.

편집 : 더 미적으로 즐거운 버전 (258 바이트)

TreeForm[#/.{a_,_,_}:>a,VertexRenderingFunction->(#2~Text~#&),VertexCoordinateRules->Cases[#,{_,_},Infinity,Heads->True]]&@(If[PrimeQ@#,{##},{##}@@#0@@@({{#,#3-#4{1,√3}/2,#4/2},{#2/#,#3-#4{-1,√3}/2,#4/2}}&[Max@Nearest[Divisors@#,√#],##])]&[#,{0,0},1])&

결과는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


3
Sqrt@#-> #^.5(물론 접두사 표기법을 사용할 수는 없지만 사용할 Nearest수는 있습니다 Max@).
Martin Ender

5
그것은 규칙을 따르지만 그 나무는 미적으로 유쾌한 xD 와는 거리가 멀다
Beta Decay

2
아름다움은 보는 사람의 눈에있다 :)
Nelson

1
이것이 유효한지 확실하지 않습니다. 예제와 달리 각 행의 노드 간격이 균등하지 않습니다. 또한 줄이 올바른 숫자에 연결되지 않습니다.
Mego

1
@ Mego 글쎄, OP 는 유효 하다고 말했다 .
R. Kap

3

, 302 바이트

≔⟦⟦N⁰θ⁰¦⁰⟧⟧θFθ«≔§ι⁰ζ≔⌈E…·²Xζ·⁵∧¬﹪ζκκη¿η«F⟦η÷ζη⟧«≔⟦κ⊕§ι¹Iκ⁰¦⁰⟧κ⊞ικ⊞θκ»⊞υι»»≔…⁰⌈Eθ§ι¹ηF⮌竧≔ηι⊕⌈⟦⁰⌈Eυ∧⁼§κ¹ι÷Σ⟦¹§§κ⁵¦⁴‹⁹§§κ⁵¦⁰§§κ⁶¦³‹⁹§§κ⁶¦⁰±L§κ²⟧²⟧FυF²§≔κ⁺³λ⁺⁺§ηι∨⊖L§§κ⁺⁵벦¹§§κ⁺⁵λ⁺³λ»Fυ«§≔§ι⁵¦³⁻⁻§ι³§η§ι¹∨⊖L§§ι⁵¦²¦¹§≔§ι⁶¦³⁻⁺⁺§ι³L§ι²§η§ι¹‹⁹§§ι⁶¦⁰»F⊕Lη«Fθ«F⁼§κ¹ι«←⸿M§κ³→F‹⁵Lκ«↙P↙§ηι↗»§κ²↓F‹⁵LκP↘§ηι»»M⊕§ηι↓

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 상세 버전은 매우 상세하므로 기본 알고리즘을 JavaScript로 음역합니다.

u = []; // predefined variable, used as list of branches
q = [[+s, 0, s, 0, 0]]; // list of nodes starts with the root.
for (i of q) { // iterate nodes, includes new nodes
    z = i[0]; // get node value
    h = Math.max(...[...Array(Math.floor(z ** 0.5) + 1).keys()].slice(2).filter(
        k => z % k < 1)); // find largest factor not above square root
    if (h) {
        for (k of [h, z / h]) {
            k = [k, i[1] + 1, `${k}`, 0, 0]; // create child node
            i.push(k); // add each child to parent (indices 5 and 6)
            q.push(k); // and to master nodelist
        }
        u.push(i);
    }
}
h = new Array(Math.max(...q.map(i => i[1]))); // list of branch heights
for (i = h.length; i --> 0; ) {
    // find branch height needed to space immediate children apart at this depth
    h[i] = 1 + Math.max(...u.map(k => k[1] == j && // filter on depth
        1 + k[5][3] + (k[5][0] > 9) + k[6][2] + (k[6][0] > 9) - k[2].length
        >> 1)); // current overlap, halved, rounded up
    // calculate the new margins on all the nodes
    for (k of u) {
        k[3] = h[i] + (k[5][2].length - 1 || 1) + k[5][3]; // left
        k[4] = h[i] + (k[6][2].length - 1 || 1) + k[6][4]; // right
    }
}
// calculate the absolute left margin of all the nodes under the root
for (i of u) {
    i[5][3] = i[3] - h[i[1]] - (i[5][2].length - 1 || 1);
    i[6][3] = i[3] + i[2].length + h[i[1]] - (i[6][0] > 9);
}
// print the nodes (sorry, no transliteration available)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.