Xây dựng một cây chia ước tính thẩm mỹ


43

Cây chia ước tính thẩm mỹ là cây chia các đầu vào n, với bất kỳ số tổng hợp nào m, có hai nút con là cặp ước số gần nhất với căn bậc hai của m. Nút bên trái phải là ước số nhỏ hơn mvà nút bên phải là ước số lớn hơn của m. Một số nguyên tố trong cây nên không có nút con. Cây của bạn có thể ở dạng văn bản nghệ thuật hoặc một hình ảnh. Các quy tắc cho đầu ra nghệ thuật văn bản như sau.

Quy tắc khoảng cách

Để loại bỏ các nút trên cây, chúng ta có các quy tắc sau:

  • Các nút ở độ sâu nhất định từ gốc phải nằm trên cùng một dòng văn bản trong đầu ra.
  / \ KHÔNG PHẢI / \  
 / \ / 3
2 3 2
  • Đối với các nút bên trái, nhánh đến phải ở phía trên bên phải nếu nút là số có một chữ số, mặt khác, ngay phía trên chữ số cuối cùng. Thí dụ:
 / VÀ /
3 720
  • Đối với các nút bên phải, nhánh đến phải nằm ở phía trên bên trái nếu nút là số có một chữ số, mặt khác, ngay phía trên chữ số đầu tiên. Thí dụ:
\ VÀ \
 7 243
  • Đối với các nhánh bên trái, nhánh nên bắt đầu một khoảng trắng ở bên trái của số. Thí dụ:
  275
 /
11
  • Đối với các nhánh bên phải, nhánh nên bắt đầu một khoảng trắng ở bên phải của số. Thí dụ:
275
   \
   25
  • Bất kỳ hai nút trên cùng một cấp độ của cây nên có tối thiểu hai khoảng cách giữa chúng. Đồng thời, bất kỳ hai cây con nào trên cùng một cấp độ của cây nên có càng ít khoảng cách giữa chúng càng tốt.
Cây này không hoạt động vì ** cây con ** quá gần.

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

Trong khi cây này có đủ không gian giữa các nhánh của nó.

         504           
        / \          
       / \         
      / \        
     / \       
    / \      
   21 ... 24     
  / \ ... / \    
 / \ ... / \   
3 7 ... 4 6  
        ... / \ / \ 
        ... 2 2 2 3
  • Nếu bất kỳ hai cây con quá gần nhau trên một cây, chúng có thể được phân tách bằng cách thêm một hàng nhánh khác /\vào cây phía trên bố mẹ.
   441                              
  / \ Hàng cuối cùng chưa được điền và chúng tôi đã hết dung lượng.
 21 21
/ \ / \

Thêm một hàng nhánh khác

     441                              
    / \ Hầu như, nhưng 7 và 3 quá gần nhau.
   / \ Một hàng nữa nên làm điều đó.
  21 21
 / \ / \
3 7 3 7

Thêm một hàng nhánh khác

      441
     / \ Và chúng ta đã hoàn thành.
    / \
   / \
  21 21
 / \ / \
3 7 3 7

Ví dụ

Lấy ví dụ đầy đủ, cây chia 24 sẽ trông như thế này:

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

4 và 6 là cặp ước gần nhất với căn bậc hai của 24. 4 nằm bên trái, vì nó nhỏ hơn. Trên dòng tiếp theo, số 2 ở bên trái của 3, vì nó nhỏ hơn.

Cây chia cho 63 sẽ giống như:

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

Trong cây không chính xác, 3 và 21 không phải là cặp ước gần nhất với căn bậc hai của 63 và 3 và 7 không được sắp xếp đúng. Vị trí chi nhánh trên 21 là chính xác, mặc dù.

Đối với 42, bạn nên có:

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

Chúng ta hãy xem 720. Lưu ý rằng chúng ta cần năm cấp độ của các nhánh 720để các 2430cây con được đặt cách nhau chính xác. Ngoài ra, lưu ý rằng 2430có hai cấp nhánh vì 46có các nút con cần khoảng cách chính xác và các nút con 30cần phải ở cùng cấp độ với các nút con của 24.

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

Các thách thức

  • Nhiệm vụ của bạn là xây dựng một cây chia ước tính có khoảng cách chính xác cho đầu vào n, trong đó nmột số nguyên dương lớn hơn 1.
  • Đầu ra của bạn có thể chứa các khoảng trắng ở đầu và cuối và các dòng mới hàng đầu và cuối, nhưng phải tuân theo các quy tắc khoảng cách được đưa ra ở trên.
  • Đầu ra của bạn được phép là: văn bản nghệ thuật, một hình ảnh (các định dạng khác sẽ được thêm vào, nếu cần).
  • Đối với hình ảnh, đảm bảo các nút của cây của bạn có khoảng cách đều nhau và các nút có cùng độ cao trong cây có cùng độ cao trong ảnh.
  • Đây là mã golf. Số byte ít nhất (hoặc tương đương) thắng.

Tín dụng cho Stewie Griffin vì đã nghĩ ra ý tưởng này, và cảm ơn Peter Taylor, Martin Ender, Mego và Eᴀsᴛᴇʀʟʏ Iʀᴋ vì sự giúp đỡ của họ trong việc viết lại đặc tả. Như thường lệ, bất kỳ đề xuất hoặc chỉnh sửa đều được đánh giá cao. Chúc may mắn và chơi golf tốt!

Nhiều trường hợp thử nghiệm:

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

Cảm ơn bạn cho thử thách này. Bây giờ tôi có thể hình dung những thứ này mà không cần vẽ chúng mỗi lần: D
Conor O'Brien

Cây có cần trông giống như các ví dụ không, hoặc tôi có thể sử dụng hàm Mathicala tích hợp không? Nó trông như thế này , nhưng với yếu tố.
JungHwan tối

@JHM Tôi biết tôi nên giữ thẻ đầu ra đồ họa . Có, bạn có thể sử dụng tích hợp sẵn. Tôi sẽ chỉnh sửa thử thách.
Sherlock9

Câu trả lời:


29

Python 2 , 711 651 575 559 554 547 539 540 530 522 byte

Sau bốn tháng cố gắng viết câu trả lời này, chạy vào một bức tường, để nó trong một tuần, rửa sạch, lặp lại, cuối cùng tôi cũng đã hoàn thành một câu trả lời nghệ thuật ASCII thích hợp cho thử thách này. Tất cả những gì còn lại là chơi golf, và vì vậy, những gợi ý chơi gôn rất được hoan nghênh. Hãy thử trực tuyến!

Golf: -60 byte từ việc đổi tên một số chức năng thường được sử dụng và thay đổi cách trả về kết quả. -73 byte từ việc thay đổi cách kiểm tra độ cao của cây con, cách tính các biến khoảng cách và kết quả được trả về. -3 byte từ sự isdigit()thay thế của FlipTack . -16 byte chơi golf isdigit()thay thế hơn nữa và thay thế "" bằng E. -5 byte từ các cải tiến nhỏ và thay đổi từ Python 3 sang Python 2. -7 byte từ sửa đổi cách trả về kết quả. -8 byte từ một thay đổi nhỏ đến cách Axác định, thay đổi cách Txác định và thêm W, bằng cách sử dụng giả thuyết rằng bất kỳ cây con nào có ít nhất một nhánh dài hơn so với đối tác của nó, nhất thiết phải dài hơn so với đối tác của nó , loại bỏQhoàn toàn, và chỉnh sửa làm thế nào kết quả được trả về. -10 byte từ việc sử dụng A<10thay vì L(S(A))<2cho AB. -8 byte từ việc thay đổi mặc định Hthành [0]do mã tránh được vấn đề về các đối số mặc định có thể thay đổi bằng cách không bao giờ Hthay đổi, thay đổi cách qxác định bằng cách sử dụng (B>9)thay vì 1-(B<10), loại bỏ phoàn toàn và tạo Fthay thế cho p+q-M.

Sửa lỗi: Giả thuyết đã sai, ví dụ trong 11**9 = 2357947691. +1 byte

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

Giải trình

Toàn bộ chức năng có thể được rút ngắn xuống còn khoảng bốn bước:

  1. Xác định cặp ước lớn nhất của n, AB.
  2. Tạo các cây con AB, vẽ lại khi cần thiết.
  3. Xác định số lượng không gian nên đi giữa các cây con.
  4. Vẽ và trả lại cây chia mới.

Tôi sẽ đi qua từng bước theo thứ tự.

Bước 1. Đây là bước dễ nhất, khá thẳng thắn. Kiểm tra mọi số ztừ 1 đến căn bậc hai để biết khả năng chia hết nvà lấy số lớn nhất zvà số n//zđó khớp. Return chỉ str(n)nếu nlà số nguyên tố (hoặc A==1hay B==n)

Bước 2. Vẽ các cây con của ABlấy số /\nhánh giữa các nút trong các cây con. Để làm điều này, chúng ta lấy các chỉ số của mỗi bước có chữ số trong đó, lấy các khác biệt đầu tiên của các chỉ số và trừ đi 1 lần nữa. Khi chúng ta có độ cao, chúng ta so sánh chúng để có giá trị lớn nhất và vẽ lại các cây con với độ cao mới.

Tôi có một nghi ngờ lén lút rằng cây con có tổng thể cao hơn luôn có các nhánh dài bằng hoặc bằng các nhánh trên cây con ngắn hơn và tôi có thể sử dụng nó để đánh gôn, nhưng tôi chưa có bằng chứng nào về điều này. Ví dụ trong 11**9 = 2357947691.

Bước 3. Bước này là những gì phải mất vài tháng để viết. Bước 2 mất vài ngày để viết và gỡ lỗi, nhưng việc tìm ra các công thức phù hợp cho khoảng cách mất nhiều thời gian. Tôi sẽ xem liệu tôi có thể cô đọng lại những gì tôi đã tìm ra trong một vài đoạn không. Lưu ý rằng một số mã trong giải thích này đã bị loại ra khỏi mã thực.

Thứ nhất, p, q, h, P, Q, sM. plà số lượng ký tự từ cuối nhánh bên trái /đến cuối bên phải của cây con bên trái. qlà số lượng ký tự từ đầu bên trái của cây con bên phải đến cuối nhánh bên phải /. hlà số nhánh giữa gốc và cây con. PQchỉ là nghịch đảo của pqrất hữu ích cho việc đặt các khoảng trống xung quanh /\các nhánh lên đến gốc n. slà số lượng khoảng trắng thêm vào giữa hai cây con. Mlà đơn giản nhất; đó là chiều dài của n. Đặt đồ họa:

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

Công thức để xác định plà : p = len(x[0]) - x[0].rindex(str(A)[-1]) - (A<10), độ dài, trừ chỉ số 0 của ký tự cuối cùng trong A, trừ đi một hiệu chỉnh cho As một chữ số .

Công thức để xác định qlà: q = y[0].index(str(B)[0]) + (B>9)chỉ số của ký tự đầu tiên trong B, cộng với hiệu chỉnh cho chỉ mục bằng 0, trừ đi một hiệu chỉnh cho các chữ số đơn B(kết hợp thành một hiệu chỉnh cho nhiều chữ số B).

Công thức để xác định hlà : h = H[0] or (p+q+M%2+2-M)//2 or 1. Hoặc là chúng tôi lấy từ một xác định trước Hcó nghĩa là chúng tôi vẽ lại cây, chúng tôi sử dụng (from_the_left + from_the_right + parity_space + 2 - len(root)) // 2)hoặc chúng tôi sử dụng số lượng cấp nhánh tối thiểu, 1.

Công thức để xác định slà : s = 2*h+M-p-q. Chúng tôi trừ pqtừ số lượng khoảng cách giữa các nhánh của chúng rộng nhất 2*h + M.

Bước 4. Và cuối cùng chúng tôi kết hợp tất cả lại. Đầu tiên chúng ta tạo gốc, [" "*(P+h)+Z+" "*(Q+h)]sau đó chúng ta đặt các nhánh xuống các cây con [" "*(P+J)+"/"+" "*(2*h+M-2*J-2)+"\\"+" "*(Q+J)for J in G(h)][::-1], và cuối cùng chúng ta đặt các cây con cách đều nhau , [(" "*(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)))].

Et voilà! Chúng tôi có cho mình một cây chia ước tính thẩm mỹ!

Ungolfing:

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

isdigitKiểm tra của bạn có thể được '/'<x[i].strip()[0]<':'?
FlipTack

14

Toán học, 96 86 81 79 78 byte

Cảm ơn @MartinEnder cho 2 byte.

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

Đầu ra trông như thế này:

nhập mô tả hình ảnh ở đây

Giải trình

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

Tạo danh sách các ước của đầu vào. Tìm phần tử gần nhất với căn bậc hai của đầu vào. ( Maxlà để làm phẳng đầu ra)

#2[#,#2/#]&

Tìm ước số khác bằng cách chia đầu vào cho ước số tìm thấy ở trên, áp dụng đầu vào làm đầu kết quả.

#0/@

Lặp lại quá trình.

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

Nếu đầu vào là số nguyên tố, đừng làm gì cả.

TreeForm

Định dạng đầu ra.

Chỉnh sửa: Phiên bản có tính thẩm mỹ cao hơn (258 byte)

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

Đầu ra trông như thế này:

nhập mô tả hình ảnh ở đây


3
Sqrt@#-> #^.5(tất nhiên sau đó bạn không thể sử dụng ký hiệu infix cho Nearestnhưng sau đó bạn có thể sử dụng Max@).
Martin Ender

5
Nó tuân theo các quy tắc, nhưng cây đó khác xa về mặt thẩm mỹ xD
Beta Decay

2
Vẻ đẹp là trong mắt của kẻ si tình :)
Nelson

1
Tôi không chắc chắn rằng điều này là hợp lệ. Không giống như các ví dụ, các nút trên mỗi hàng không cách đều nhau. Ngoài ra, các dòng không kết nối với chữ số chính xác.
Mego

1
@Mego Vâng, OP nói nó hợp lệ.
R. Kap

3

Than , 302 byte

≔⟦⟦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⊕§ηι↓

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Vì phiên bản dài dòng rất dài dòng, anh ta là phiên âm JavaScript của thuật toán chính:

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.