Tính toán hàm nhị phân hiệu quả nhất


13

Hôm nay, chúng ta sẽ tính toán hàm nhị phân hiệu quả nhất. Cụ thể hơn, chúng ta sẽ tính toán hàm, khi một biểu thức được tạo từ việc áp dụng hàm cho đầu vào không đổi 0 hoặc đầu ra của chính nó, có thể biểu diễn tất cả các số nguyên dương với các biểu thức ngắn nhất có thể, đặt mức độ ưu tiên cao hơn cho các số nguyên nhỏ hơn.

Chức năng này được xây dựng như sau:

Đối với mỗi số nguyên, bắt đầu từ 1 và đi lên, chọn biểu thức ngắn nhất mà chúng ta chưa gán đầu ra và biến số nguyên đó thành đầu ra của biểu thức đó. Các mối quan hệ về độ dài biểu thức sẽ bị phá vỡ bởi đối số bên trái nhỏ hơn và sau đó bằng đối số bên phải nhỏ hơn. Đây là cách nó hoạt động:

  • Ban đầu, 1 không được chỉ định. Biểu thức chưa được gán ngắn nhất là f(0, 0), vì vậy chúng tôi sẽ đặt thành 1.

  • Bây giờ, 2 là không được chỉ định. Các biểu thức chưa được gán ngắn nhất là f(f(0, 0), 0)= f(1, 0)f(0, f(0, 0))= f(0, 1). Ties bị phá vỡ đối với đối số bên trái nhỏ hơn, vì vậy f(0, 1) = 2.

  • Biểu thức chưa được gán ngắn nhất còn lại là f(f(0, 0), 0)= f(1, 0), vì vậy f(1, 0) = 3.

  • Bây giờ, chúng tôi đã hết các biểu thức chỉ với 2 fgiây và 3 0giây, vì vậy chúng tôi sẽ phải thêm một biểu thức nữa. Phá vỡ mối quan hệ bằng lập luận trái, sau đó tranh luận phải, chúng ta có được f(0, 2) = 4, kể từ đó f(0, f(0, f(0, 0))) = f(0, f(0, 1)) = f(0, 2).

  • Tiếp tục, chúng tôi có f(0, 3) = 5, f(1, 1) = 6, f(2, 0) = 7, f(3, 0) = 8, f(0, 4) = 9, ...

Đây là bảng tôi đã điền cho một vài giá trị đầu tiên:

    0  1  2  3  4  5  6  7  8
 /---------------------------
0|  1  2  4  5  9 10 11 12 13
1|  3  6 14 15 37 38 39 40 41
2|  7 16 42 43
3|  8 17 44 45
4| 18 46
5| 19 47
6| 20 48
7| 21 49
8| 22 50

Một cách khác để xem xét nó là mỗi đầu ra có một kích thước, bằng tổng kích thước của các đầu vào của nó cộng với một. Bảng được điền theo thứ tự tăng kích thước đầu ra, các mối quan hệ bị phá vỡ bằng cách giảm thiểu đầu vào bên trái sau đó đầu vào bên phải.

Thách thức của bạn là, đưa ra hai số nguyên không âm là đầu vào, tính toán và xuất giá trị của hàm này. Đây là mã golf. Giải pháp ngắn nhất, tính bằng byte, thắng. Sơ hở tiêu chuẩn bị cấm.


Trông tương tự A072766 , nhưng khác với bắt đầu từ f (3, 1).
kennytm

2
Đây là thử thách đầu tiên trong một thời gian đánh đố tôi phần nào để tính toán hiệu quả. Tôi tin rằng một cái gì đó có thể với số Catalan, nhưng không thể nghĩ ngay đến một giải pháp. Hmm ...
orlp

2
Được rồi, vì vậy tôi không nghĩ rằng nó sẽ tạo ra một câu trả lời tốt cho việc chơi gôn, nhưng những gì bạn có thể làm để làm cho nó hiệu quả một cách hợp lý là liên tục trừ các số Catalan khỏi các đối số chức năng cho đến khi chúng nhỏ hơn số Catalan tiếp theo. Sau đó, bạn đã tìm thấy độ dài của biểu thức của họ. Sau đó, bạn có thể sử dụng các chức năng xếp hạng / hủy kết nối từ bài báo này , với sửa đổi, để tính kết quả. Có lẽ sau khi làm tất cả những gì có thể 'hủy bỏ' các đoạn mã ở giữa và tìm một giải pháp hợp lý thanh lịch.
orlp

Trên thực tế, cách tiếp cận từ nhận xét trước đây của tôi không hoạt động. ((0, (0, (0, 0))), 0)nhỏ hơn về mặt từ vựng (((0, 0), 0), (0, 0)), tuy nhiên cái sau có cạnh trái nhỏ hơn.
orlp

Câu trả lời:


6

Haskell, 110 byte

f q=head[i|let c=[(-1,0)]:[[(f a,f b)|n<-[0..k],a<-c!!n,b<-c!!(k-n)]|k<-[0..]],(p,i)<-zip(concat c)[0..],p==q]

Đối số ở đây được coi là tuple (x,y). Khá giống với câu trả lời ở trên, nhưng danh sách tra cứu chỉ giữ các cặp chỉ số trái và phải thay vì các cây.


1
Câu trả lời tốt đẹp! head[...][...]!!0(p,i)<-zip(concat c)[0..]có thể được rút ngắn xuống còn (i,p)<-zip[0..]$id=<<c.
Laikoni

Cảm ơn những cải tiến! Chắc chắn thêm id=<<vào tiết mục :)
halfflat

5

Python 3, 154 byte

b=lambda n:[(l,r)for k in range(1,n)for l in b(k)for r in b(n-k)]+[0]*(n<2)
def f(x,y):r=sum((b(n)for n in range(1,x+y+3)),[]);return r.index((r[x],r[y]))

Nó không nhanh và cũng không quá gôn, nhưng đó là một khởi đầu.


5

Ồ Tôi thực sự quản lý để thực hiện một thuật toán tính toán hiệu quả. Tôi đã không mong đợi điều này lúc đầu. Giải pháp khá thanh lịch. Nó liên tục suy ra ngày càng nhiều, sau đó đệ quy tất cả các trường hợp cơ bản bằng 0. Trong câu trả lời này, hàm C (n) biểu thị các số Catalan .

Bước đầu tiên quan trọng là thừa nhận rằng có các giá trị C (0) = 1 có độ dài bằng 0 (cụ thể là 0), C (1) = 1 giá trị có độ dài một (cụ thể là f (0, 0)), C (2) = 2 giá trị có độ dài hai (f (0, f (0, 0)) và f (f (0, 0), 0)).

Điều này có nghĩa là nếu chúng ta tìm biểu thức thứ n và chúng ta tìm thấy k lớn nhất sao cho C (0) + C (1) + ... + C (k) <= n thì chúng ta biết rằng n có độ dài k .

Nhưng bây giờ chúng ta có thể tiếp tục! Bởi vì biểu thức mà chúng ta tìm kiếm là biểu thức n - C (0) - C (1) - ... - C (k) trong lớp độ dài của nó.

Bây giờ chúng ta có thể sử dụng một mẹo tương tự để tìm độ dài của đoạn bên trái, và sau đó là thứ hạng trong tiểu mục đó. Và sau đó tái diễn trên các cấp bậc mà chúng tôi tìm thấy!

Nó phát hiện ra rằng f (5030, 3749) = 1542317211 trong chớp mắt.

Python, không biên dịch

def C(n):
    r = 1
    for i in range(n):
        r *= 2*n - i
        r //= i + 1
    return r//(n+1)

def unrank(n):
    if n == 0: return 0

    l = 0
    while C(l) <= n:
        n -= C(l)
        l += 1

    right_l = l - 1
    while right_l and n >= C(l - 1 - right_l) * C(right_l):
        n -= C(l - 1 - right_l) * C(right_l)
        right_l -= 1

    right_num = C(right_l)

    r_rank = n % right_num
    l_rank = n // right_num

    for sz in range(l - 1 - right_l): l_rank += C(sz)
    for sz in range(right_l): r_rank += C(sz)

    return (unrank(l_rank), unrank(r_rank))

def rank(e):
    if e == 0: return 0
    left, right = e

    l = str(e).count("(")
    left_l = str(left).count("(")
    right_l = str(right).count("(")
    right_num = C(right_l)

    n = sum(C(sz) for sz in range(l))
    n += sum(C(sz)*C(l - 1 - sz) for sz in range(left_l))

    n += (rank(left) - sum(C(sz) for sz in range(left_l))) * C(right_l)
    n += rank(right) - sum(C(sz) for sz in range(right_l))

    return n

def f(x, y):
    return rank((unrank(x), unrank(y)))

Tôi khá chắc chắn Tôi đang thực hiện một loạt các tính toán không cần thiết và rất nhiều bước giữa có thể được gỡ bỏ.

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.