가장 효율적인 이진 함수 계산


13

오늘, 우리는 가장 효율적인 이진 함수를 계산할 것입니다. 보다 구체적으로, 함수를 상수 입력 0 또는 자체 출력에 적용하여 식을 만들 때 가능한 가장 짧은 식으로 모든 양의 정수를 나타낼 수있는 함수를 계산하여 작은 정수에 우선 순위를 둡니다.

이 기능은 다음과 같이 구성됩니다.

1부터 시작하여 위쪽으로 올라가는 각 정수에 대해 아직 출력을 할당하지 않은 가장 짧은 표현식을 선택하고 해당 정수를 해당 표현식의 출력으로 만듭니다. 표현식 길이의 타이는 더 작은 왼쪽 인수로, 그 다음 작은 오른쪽 인수로 끊어집니다. 작동 방식은 다음과 같습니다.

  • 처음에는 1이 할당되지 않았습니다. 할당되지 않은 가장 짧은 표현은입니다 f(0, 0). 그래서 1로 설정하겠습니다.

  • 이제 2가 할당되지 않았습니다. 할당되지 않은 가장 짧은 표현식은 f(f(0, 0), 0)= f(1, 0)f(0, f(0, 0))= f(0, 1)입니다. 동점은 더 작은 좌익으로 나뉘어진다 f(0, 1) = 2.

  • 나머지 최단 할당 식이다 f(f(0, 0), 0)= f(1, 0)그래서 f(1, 0) = 3.

  • 이제 우리는 2 f초와 3 0초만 있는 표현이 없으므로 각각 하나씩 더 추가해야합니다. 왼쪽 인수, 오른쪽 인수로 관계를 끊기 f(0, 2) = 4때문에 f(0, f(0, f(0, 0))) = f(0, f(0, 1)) = f(0, 2).

  • 계속해서, 우리가 f(0, 3) = 5, f(1, 1) = 6, f(2, 0) = 7, f(3, 0) = 8, f(0, 4) = 9, ...

다음은 처음 몇 가지 값에 대해 작성한 표입니다.

    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

그것을 보는 또 다른 방법은 각 출력의 크기에 입력 크기의 합에 1을 더한 크기와 같습니다. 테이블은 출력 크기의 증가 순서대로 채워지며 왼쪽 입력과 오른쪽 입력을 최소화하여 연결이 끊어집니다.

입력으로 두 개의 음이 아닌 정수가 주어지면이 함수의 값을 계산하고 출력하십시오. 이것은 코드 골프입니다. 가장 짧은 솔루션 (바이트)이 이깁니다. 표준 허점 은 금지되어 있습니다.


A072766 과 비슷 하지만 f (3, 1)부터 다릅니다.
kennytm

2
이것은 효율적으로 계산하기 위해 다소 당황스러운 한동안의 첫 번째 도전입니다. 나는 카탈로니아 어 숫자로 뭔가 가능하다고 생각하지만 즉시 해결책을 생각할 수는 없습니다. 흠 ...
orlp

2
좋아, 그래서 그것이 좋은 골프 답변을 만들 것이라고 생각하지 않지만, 합리적으로 효율적으로 만들기 위해 할 수있는 일은 다음 카탈로니아 어 숫자보다 작을 때까지 함수 인수에서 카탈로니아 어 숫자를 반복적으로 빼는 것입니다. 그런 다음 표현의 길이를 찾았습니다. 그런 다음 이 백서 의 순위 / 랭킹 해제 기능 수정하여 결과를 계산할 수 있습니다. 아마도 모든 것을 한 후에 중간에 약간의 코드를 '취소'하고 합리적으로 우아한 솔루션을 찾을 수 있습니다.
orlp

사실, 내 이전 의견의 접근 방식이 작동하지 않습니다. ((0, (0, (0, 0))), 0)은 사전 순으로보다 작지만 (((0, 0), 0), (0, 0))후자는 왼쪽이 더 작습니다.
orlp

답변:


6

하스켈, 110 바이트

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]

여기서 논쟁은 튜플로 간주 (x,y)됩니다. 위의 답변과 매우 유사하지만 조회 목록에는 나무 대신 왼쪽과 오른쪽 색인 쌍이 있습니다.


1
좋은 대답입니다! head[...][...]!!0(p,i)<-zip(concat c)[0..]단축 할 수있다 (i,p)<-zip[0..]$id=<<c.
Laikoni

개선 주셔서 감사합니다! 확실히 id=<<레퍼토리에 추가 :)
halfflat

5

파이썬 3, 154 바이트

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

빠르지도 골프도 아니지만 시작입니다.


5

와! 실제로 효율적인 계산 알고리즘을 만들었습니다. 나는 이것을 처음에는 기대하지 않았다. 해결책은 매우 우아합니다. 반복해서 더 많이 추론하고 0의 기본 사례까지 반복합니다.이 답변에서 C (n) 함수는 카탈로니아 어 숫자를 나타냅니다 .

중요한 첫 번째 단계는 길이 0의 1 (즉, 0)의 C (0) = 1 값, 길이 1의 1 (즉, f (0, 0))의 1 (값), C (2) = 1이라는 점을 인정하는 것입니다. 길이 2의 두 값 (f (0, f (0, 0)) 및 f (f (0, 0), 0)).

이것은 우리가 n 번째 표현을 찾고 C (0) + C (1) + ... + C (k) <= n과 같은 가장 큰 k를 찾으면 n의 길이가 k임을 알 수 있습니다. .

그러나 지금 우리는 계속할 수 있습니다! 우리가 찾는 표현식은 길이 클래스에서 n-C (0)-C (1)-...-C (k) 번째 표현식입니다.

이제 유사한 트릭을 사용하여 왼쪽 세그먼트의 길이를 찾은 다음 해당 하위 섹션 내의 순위를 찾을 수 있습니다. 그리고 우리가 찾은 순위에 재귀하십시오!

눈의 깜박임에서 f (5030, 3749) = 1542317211임을 발견했습니다.

비경쟁 Python

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

나는 불필요한 계산을 많이하고 있으며 많은 중간 단계를 제거 할 수 있다고 확신합니다.

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