Tính xác suất chính xác và nhanh chóng


10

[Đây là một câu hỏi đối tác để tính toán xác suất chính xác ]

Nhiệm vụ này là về viết mã để tính xác suất chính xác và nhanh chóng . Đầu ra phải là một xác suất chính xác được viết dưới dạng phân số ở dạng giảm nhất. Đó là nó không bao giờ nên đầu ra 4/8mà là 1/2.

Đối với một số số nguyên dương n, hãy xem xét một chuỗi ngẫu nhiên đồng nhất có độ dài 1s và -1 nvà gọi nó là A. Bây giờ nối với Agiá trị đầu tiên của nó. Đó là A[1] = A[n+1]nếu lập chỉ mục từ 1. Abây giờ có độ dài n+1. Bây giờ cũng xem xét một chuỗi độ dài ngẫu nhiên thứ hai nncác giá trị đầu tiên là -1, 0 hoặc 1 với xác suất 1 / 4,1 / 2, 1/4 mỗi và gọi nó là B.

Bây giờ hãy xem xét sản phẩm bên trong của A[1,...,n]Bvà sản phẩm bên trong của A[2,...,n+1]B.

Ví dụ, xem xét n=3. Các giá trị có thể cho ABcó thể là A = [-1,1,1,-1]B=[0,1,-1]. Trong trường hợp này, hai sản phẩm bên trong là 02.

Mã của bạn phải xuất xác suất rằng cả hai sản phẩm bên trong đều bằng không.

Sao chép bảng do Martin Büttner sản xuất, chúng tôi có các kết quả mẫu sau.

n   P(n)
1   1/2
2   3/8
3   7/32
4   89/512
5   269/2048
6   903/8192
7   3035/32768
8   169801/2097152

Ngôn ngữ và thư viện

Bạn có thể sử dụng bất kỳ ngôn ngữ và thư viện có sẵn miễn phí nào bạn muốn. Tôi phải có khả năng chạy mã của bạn, vì vậy vui lòng bao gồm một lời giải thích đầy đủ về cách chạy / biên dịch mã của bạn trong linux nếu có thể.

Nhiệm vụ

Mã của bạn phải bắt đầu bằng n=1và đưa ra đầu ra chính xác cho mỗi n tăng trên một dòng riêng biệt. Nó sẽ dừng lại sau 10 giây.

Điểm số

Điểm số chỉ đơn giản là mức cao nhất nđạt được trước khi mã của bạn dừng sau 10 giây khi chạy trên máy tính của tôi. Nếu có hòa, người chiến thắng sẽ là người giành được điểm số cao nhất nhanh nhất.

Bảng mục

  • n = 64trong Python . Phiên bản 1 của Mitch Schwartz
  • n = 106trong Python . Phiên bản ngày 11 tháng 6 năm 2015 bởi Mitch Schwartz
  • n = 151trong C ++ . Câu trả lời của cảng Mitch Schwartz bởi kirbyfan64sos
  • n = 165trong Python . Phiên bản ngày 11 tháng 6 năm 2015 phiên bản "cắt tỉa" của Mitch Schwartz với N_MAX = 165.
  • n = 945trong Python by Min_25 bằng cách sử dụng một công thức chính xác. Kinh ngạc!
  • n = 1228trong Python của Mitch Schwartz sử dụng một công thức chính xác khác (dựa trên câu trả lời trước đó của Min_25).
  • n = 2761trong Python của Mitch Schwartz bằng cách sử dụng triển khai nhanh hơn cùng một công thức chính xác.
  • n = 3250trong Python sử dụng Pypy của Mitch Schwartz bằng cách sử dụng tương tự. Điểm này cần pypy MitchSchwartz-faster.py |tailphải tránh điều khiển di chuyển trên đầu.

Tôi tự hỏi nếu một giải pháp numpy sẽ chạy nhanh hơn Boost C ++?
qwr

@qwr Tôi nghĩ numpy, numba và cython đều thú vị khi chúng được giữ trong gia đình Python.

2
Tôi muốn thấy nhiều hơn về các vấn đề mã nhanh nhất này
qwr

@qwr đó là loại câu hỏi yêu thích của tôi ... Cảm ơn bạn! Thách thức là tìm ra một thứ không liên quan đến việc mã hóa chính xác cùng một thuật toán bằng ngôn ngữ cấp thấp nhất mà bạn có thể tìm thấy.

Bạn đang viết kết quả lên bàn điều khiển hoặc vào một tập tin? Sử dụng pypy và viết vào một tập tin có vẻ là nhanh nhất đối với tôi. Bảng điều khiển làm chậm quá trình đáng kể.
gnibbler

Câu trả lời:


24

Con trăn

Một công thức dạng đóng p(n)

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

Một chức năng tạo hàm mũ của p(n)

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

trong đó I_0(x)chức năng Bessel được sửa đổi của loại đầu tiên.

Chỉnh sửa vào ngày 2015-06-11:
- đã cập nhật mã Python.

Chỉnh sửa vào ngày 2015-06-13:
- thêm bằng chứng về công thức trên.
- Đã sửa time_limit.
- thêm mã PARI / GP.

Con trăn

def solve():
  # straightforward implementation

  from time import time
  from itertools import count

  def binom(n, r):
    return facts[n] // (facts[r] * facts[n - r])

  def p(N):
    ans = 0
    for i in range(1 + N // 2):
      t = binom(2 * (N - 2 * i), N - 2 * i)
      t *= binom(N, 2 * i)
      t *= binom(4 * i, 2 * i)
      ans += t
    e = (ans & -ans).bit_length() - 1
    numer = ans >> e
    denom = 1 << (3 * N - 1 - e)
    return numer, denom

  facts = [1]
  time_limit = 10.0 + time()

  for i in count(1):
    facts.append(facts[-1] * (2 * i - 1))
    facts.append(facts[-1] * (2 * i))

    n, d = p(i)

    if time() > time_limit:
      break

    print("%d %d/%d" % (i, n, d))

solve()

PARI / GP

p(n) = polcoeff( (exp(x/2) + 1) * besseli(0, x/4) ^ 2, n) * n!;

Bằng chứng:
Vấn đề này tương tự như vấn đề đi bộ ngẫu nhiên 2 chiều (bị hạn chế).

Nếu A[i] = A[i+1]chúng ta có thể di chuyển từ (x, y)để (x+1, y+1)[1 cách], (x, y)[2 cách] hoặc (x-1, y-1)[1 cách].

Nếu A[i] != A[i+1]chúng ta có thể di chuyển từ (x, y)để (x-1, y+1)[1 cách], (x, y)[2 cách] hoặc (x+1, y-1)[1 cách].

Hãy a(n, m) = [x^m]((x+1)^n + (x-1)^n), b(n) = [x^n](1+x)^{2n}c(n)là số cách để di chuyển từ (0, 0)tới (0, 0)với nbước.

Sau đó, c(n) = \sum_{i=0}^n a(n, i) * b(i) * b(n-i).

p(n) = c(n) / 8^n, chúng ta có thể có được công thức dạng đóng ở trên.


1
Đây là .. tốt .. tuyệt vời! Làm thế nào trên trái đất bạn đã tính toán công thức chính xác?

1
Ồ Hình thức đóng luôn gọn gàng!
qwr

1
@Lembik: Tôi đã thêm một bằng chứng (thô).
Tối thiểu ngày 25

1
@qwr: Cảm ơn. Tôi cũng nghĩ thế !
Tối thiểu ngày 25

1
@ mbomb007: Vâng. Nhưng, nó là một nhiệm vụ thực hiện chứ không phải là một nhiệm vụ điện toán. Vì vậy, tôi sẽ không mã hóa nó trong C ++.
Min_25

9

Con trăn

Lưu ý: Xin chúc mừng Min_25 vì đã tìm ra giải pháp dạng đóng!

Cảm ơn vì vấn đề thú vị! Nó có thể được giải quyết bằng DP, mặc dù hiện tại tôi không cảm thấy có động lực để tối ưu hóa tốc độ để đạt điểm cao hơn. Nó có thể tốt cho golf.

Mã đạt được N=39trong vòng 10 giây trên máy tính xách tay cũ này chạy Python 2.7.5.

from time import*
from fractions import*
from collections import*

X={(1,0,0,0):1,(-1,0,0,0):1}

T=time()
N=0

while 1:
    Y=defaultdict(lambda:0)
    n=d=0
    for a,b,s,t in X:
        c=X[(a,b,s,t)]
        for A in ( (1,-1) if N else [a] ):
            for B in 1,0,0,-1:
                n+=c*(s+A*B==0==t+A*b+a*B)
                d+=c
                Y[(a,B,s+A*B,t+A*b)]+=c
    if time()>T+10: break
    N+=1
    print N,Fraction(n,d)
    X=Y

Đối với tuple (a,b,s,t): alà phần tử đầu tiên của A, blà phần tử cuối cùng của B, slà sản phẩm bên trong của A[:-1]B, và tlà sản phẩm bên trong của A[1:-1]B[:-1], sử dụng ký hiệu lát Python. Mã của tôi không lưu trữ các mảng Ahoặc Bbất cứ nơi nào, vì vậy tôi sử dụng các chữ cái đó để chỉ các phần tử tiếp theo được thêm vào AB, tương ứng. Sự lựa chọn đặt tên biến này làm cho lời giải thích hơi khó xử, nhưng cho phép một cái nhìn đẹp A*b+a*Btrong chính mã. Lưu ý rằng phần tử được thêm vào Alà phần áp chót, vì phần tử cuối cùng luôn giống với phần tử đầu tiên. Tôi đã sử dụng thủ thuật của Martin Büttner bao gồm 0hai lần trongBcác ứng cử viên để có được phân phối xác suất thích hợp. Từ điển X(được đặt tên Ycho N+1) theo dõi số lượng của tất cả các mảng có thể theo giá trị của bộ dữ liệu. Các biến nvà viết dtắt của tử số và mẫu số, đó là lý do tại sao tôi đổi tên ncâu lệnh vấn đề thành N.

Phần chính của logic là bạn có thể cập nhật từ Nđể N+1chỉ sử dụng các giá trị trong các tuple. Hai sản phẩm bên trong được chỉ định trong câu hỏi được đưa ra bởi s+A*Bt+A*b+a*B. Điều này là rõ ràng nếu bạn kiểm tra các định nghĩa một chút; lưu ý rằng [A,a][b,B]là hai yếu tố cuối cùng của mảng ABtương ứng.

Lưu ý rằng stnhỏ và bị ràng buộc theo N, và để triển khai nhanh bằng ngôn ngữ nhanh, chúng tôi có thể tránh từ điển có lợi cho mảng.

Có thể tận dụng tính đối xứng khi xem xét các giá trị chỉ khác nhau về dấu hiệu; Tôi đã không nhìn vào đó.

Ghi chú 1 : Kích thước của từ điển tăng theo phương trình bậc hai N, trong đó kích thước có nghĩa là số cặp giá trị khóa.

Ghi chú 2 : Nếu chúng ta đặt giới hạn trên N, thì chúng ta có thể cắt xén các bộ dữ liệu đó N_MAX - N <= |s|và tương tự cho t. Điều này có thể được thực hiện bằng cách chỉ định trạng thái hấp thụ, hoặc ngầm định với một biến để giữ số lượng trạng thái được cắt tỉa (sẽ cần được nhân với 8 ở mỗi lần lặp).

Cập nhật : Phiên bản này nhanh hơn:

from time import*
from fractions import*
from collections import*

N_MAX=115

def main():
    T=time()

    N=1
    Y={(1,0,0,0):1,(1,1,1,0):1}
    n=1
    thresh=N_MAX

    while time() <= T+10:
        print('%d %s'%(N,Fraction(n,8**N/4)))

        N+=1
        X=Y
        Y=defaultdict(lambda:0)
        n=0

        if thresh<2:
            print('reached MAX_N with %.2f seconds remaining'%(T+10-time()))
            return

        for a,b,s,t in X:
            if not abs(s)<thresh>=abs(t):
                continue

            c=X[(a,b,s,t)]

            # 1,1

            if not s+1 and not t+b+a: n+=c
            Y[(a,1,s+1,t+b)]+=c

            # -1,1

            if not s-1 and not t-b+a: n+=c
            Y[(a,1,s-1,t-b)]+=c

            # 1,-1

            if not s-1 and not t+b-a: n+=c
            Y[(a,-1,s-1,t+b)]+=c

            # -1,-1

            if not s+1 and not t-b-a: n+=c
            Y[(a,-1,s+1,t-b)]+=c

            # 1,0

            c+=c

            if not s and not t+b: n+=c
            Y[(a,0,s,t+b)]+=c

            # -1,0

            if not s and not t-b: n+=c
            Y[(a,0,s,t-b)]+=c

        thresh-=1

main()

Tối ưu hóa thực hiện:

  • đặt mọi thứ vào main()- truy cập biến cục bộ nhanh hơn toàn cầu
  • xử lý N=1rõ ràng để tránh kiểm tra (1,-1) if N else [a](trong đó thực thi rằng phần tử đầu tiên trong bộ dữ liệu là nhất quán, khi thêm các phần tử để Abắt đầu từ danh sách trống)
  • bỏ các vòng lặp bên trong, cũng loại bỏ sự nhân lên
  • tăng gấp đôi số lượng ccho thêm một 0để Bthay vì làm những hoạt động gấp đôi
  • mẫu số luôn luôn 8^Nvì vậy chúng ta không cần phải theo dõi nó
  • bây giờ tính đến tính đối xứng: chúng ta có thể sửa phần tử đầu tiên của Aas 1và chia mẫu số cho 2, vì các cặp hợp lệ (A,B)với A[1]=1và các cặp A[1]=-1có thể được đưa vào tương ứng một-một bằng cách phủ định A. Tương tự, chúng ta có thể sửa phần tử đầu tiên Blà không âm.
  • bây giờ với việc cắt tỉa. Bạn sẽ cần phải tìm N_MAXhiểu xem điểm số có thể đạt được trên máy của bạn. Nó có thể được viết lại để tìm một cách thích hợp N_MAXtự động bằng cách tìm kiếm nhị phân, nhưng dường như không cần thiết? Lưu ý: Chúng tôi không cần kiểm tra điều kiện cắt tỉa cho đến khi tiếp cận xung quanh N_MAX / 2, vì vậy chúng tôi có thể tăng tốc một chút bằng cách lặp lại theo hai giai đoạn, nhưng tôi quyết định không đơn giản và sạch mã.

1
Đây là một câu trả lời thực sự tuyệt vời! Bạn có thể giải thích những gì bạn đã làm trong việc tăng tốc của bạn?

@Lembik Cảm ơn bạn :) Đã thêm một lời giải thích, cộng với một tối ưu hóa nhỏ khác và làm cho nó tuân thủ Python3.
Mitch Schwartz

Trên máy tính của tôi, tôi đã có N=57phiên bản đầu tiên và phiên bản N=75thứ hai.
kirbyfan64sos

Câu trả lời của bạn thật tuyệt vời Chỉ là câu trả lời của Min_25 thậm chí còn hơn thế :)

5

Con trăn

Sử dụng ý tưởng đi bộ ngẫu nhiên của Min_25, tôi có thể đi đến một công thức khác:

p (n) = \ started {case} \ frac {\ sum _ {i = 0} ^ {\ lfloor n / 2 \ rfloor} \ binom {2i} {i} ^ 2 \ binom {n} {2i} 4 ^ {n-2i}} {8 ^ n} & n \ text {lẻ} \ \ frac {\ binom {n} {n / 2} ^ 2 + \ sum _ {i = 0} ^ {\ lfloor n / 2 \ rfloor} \ binom {2i} {i} ^ 2 \ binom {n} {2i} 4 ^ {n-2i}} {8 ^ n} & n \ text {thậm chí} \ \ end {case}

Đây là một triển khai Python dựa trên Min_25:

from time import*
from itertools import*

def main():
    def binom(n, k):
        return facts[n]/(facts[k]*facts[n-k])

    def p(n):
        numer=0
        for i in range(n/2+1):
            t=binom(2*i,i)
            t*=t
            t*=binom(n,2*i)
            t<<=2*(n-2*i)
            numer+=t
        if not n&1:
            numer+=t
        e=(numer&-numer).bit_length()-1
        numer>>=e
        denom=1<<(3*n-e)
        return numer, denom

    facts=[1]
    time_limit=time()+10

    for i in count(1):
        facts.append(facts[-1]*i)

        n,d=p(i)

        if time()>time_limit:
            break

        print("%d %d/%d"%(i,n,d))

main()

Giải thích / bằng chứng:

Đầu tiên chúng tôi giải quyết một vấn đề đếm liên quan, nơi chúng tôi cho phép A[n+1] = -A[1]; nghĩa là, phần tử bổ sung được nối với nhau Acó thể 1hoặc -1bất kể phần tử đầu tiên. Vì vậy, chúng tôi không cần phải theo dõi bao nhiêu lần A[i] = A[i+1]xảy ra. Chúng tôi có bước đi ngẫu nhiên sau:

Từ (x,y)chúng ta có thể di chuyển đến (x+1,y+1)[1 cách], (x+1,y-1)[1 cách], (x-1,y+1)[1 cách], (x-1,y-1)[1 cách], (x,y)[4 cách]

nơi xyđại diện cho hai sản phẩm dấu chấm, và chúng tôi đang đếm số cách để di chuyển từ (0,0)phải (0,0)trong nbước. Số lượng đó sau đó sẽ được nhân lên 2để tính cho thực tế Acó thể bắt đầu bằng 1hoặc -1.

Chúng tôi đề cập đến ở lại (x,y)như là một di chuyển bằng không .

Chúng tôi lặp đi lặp lại số lần di chuyển khác không i, mà phải thậm chí để quay trở lại (0,0). Chuyển động ngang và dọc tạo thành hai bước đi ngẫu nhiên một chiều độc lập, có thể được tính bằng C(i,i/2)^2, trong đó C(n,k)là hệ số nhị thức. (Để đi bộ với kcác bước bên trái và kcác bước bên phải, có nhiều C(2k,k)cách để chọn thứ tự các bước.) Ngoài ra, có nhiều C(n,i)cách để đặt các bước di chuyển và các 4^(n-i)cách để chọn các bước di chuyển bằng không. Vì vậy, chúng tôi nhận được:

a(n) = 2 * sum_{i in (0,2,4,...,n)} C(i/2,i)^2 * C(n,i) * 4^(n-i)

Bây giờ, chúng ta cần quay lại vấn đề ban đầu. Xác định một cặp cho phép (A,B)có thể chuyển đổi nếu Bchứa số không. Xác định một cặp gần như(A,B) được phép nếu A[n+1] = -A[1]và hai sản phẩm chấm đều bằng không.

Bổ đề: Đối với một số nhất định n, các cặp gần như cho phép nằm trong sự tương ứng một-một với các cặp chuyển đổi.

Chúng ta có thể (đảo ngược) chuyển đổi một cặp chuyển đổi (A,B)thành một cặp gần như cho phép (A',B')bằng cách phủ định A[m+1:]B[m+1:], trong đó mchỉ số của số 0 cuối cùng trong B. Việc kiểm tra này rất đơn giản: Nếu phần tử cuối cùng Bbằng 0, chúng ta không cần phải làm gì cả. Mặt khác, khi chúng ta phủ định phần tử cuối cùng của A, chúng ta có thể phủ định phần tử cuối cùng Bđể duy trì số hạng cuối cùng của sản phẩm dấu chấm đã dịch chuyển. Nhưng điều này phủ nhận giá trị cuối cùng của sản phẩm chấm không dịch chuyển, vì vậy chúng tôi khắc phục điều này bằng cách phủ định yếu tố thứ hai đến cuối cùng của A. Nhưng sau đó, điều này loại bỏ giá trị thứ hai đến cuối cùng của sản phẩm được chuyển đổi, vì vậy chúng tôi phủ nhận yếu tố thứ hai đến cuối cùng của B. Và như vậy, cho đến khi đạt được một yếu tố không B.

Bây giờ, chúng ta chỉ cần chỉ ra rằng không có cặp nào gần như được phép mà Bkhông chứa số không. Để một sản phẩm chấm bằng 0, chúng ta phải có số lượng 1-1điều khoản bằng nhau để hủy bỏ. Mỗi -1thuật ngữ bao gồm (1,-1)hoặc (-1,1). Vì vậy, tính chẵn lẻ của số lượng -1xảy ra được cố định theo n. Nếu các yếu tố đầu tiên và cuối cùng Acó dấu hiệu khác nhau, chúng tôi thay đổi tính chẵn lẻ, vì vậy điều này là không thể.

Vì vậy, chúng tôi nhận được

c(n) = a(n)/2 if n is odd, else a(n)/2 + C(n,n/2)^2

p(n) = c(n) / 8^n

mang đến cho công thức trên (tái lập chỉ mục với i' = i/2).

Cập nhật: Đây là phiên bản nhanh hơn sử dụng cùng một công thức:

from time import*
from itertools import*

def main():
    time_limit=time()+10

    binoms=[1]
    cb2s=[1]
    cb=1

    for n in count(1):
        if n&1:
            binoms=[a+b for a,b in zip([0]+binoms,binoms)]
        else:
            binoms=[a+b for a,b in zip([0]+binoms,binoms+[binoms[-1]])]
            cb=(cb<<2)-(cb+cb)/(n/2)
            cb2s.append(cb*cb)

        numer=0
        for i in xrange(n/2+1):
            t=cb2s[i]*binoms[min(2*i,n-2*i)]
            t<<=2*(n-2*i)
            numer+=t
        if not n&1:
            numer+=t
        e=(numer&-numer).bit_length()-1
        numer>>=e
        denom=1<<(3*n-e)

        if time()>time_limit:
            break

        print("%d %d/%d"%(n,numer,denom))

main()

Tối ưu hóa thực hiện:

  • chức năng nội tuyến p(n)
  • sử dụng tái phát cho các hệ số nhị thức C(n,k)vớik <= n/2
  • sử dụng tái phát cho các hệ số nhị thức trung tâm

Chỉ để bạn biết, p(n)không cần phải là một chức năng từng phần. Nói chung, nếu f(n) == {g(n) : n is odd; h(n) : n is even}sau đó bạn có thể viết f(n) == (n-2*floor(n/2))*g(n) + ((n+1)-2*(floor((n+1)/2)))*h(n)hoặc sử dụng n mod 2thay vì (n-2*floor(n/2)). Xem tại đây
mbomb007

1
@ mbomb007 Điều đó là hiển nhiên và không thú vị.
Mitch Schwartz

3

Giải thích về công thức của Min_25

Min_25 đã đăng một bằng chứng tuyệt vời nhưng phải mất một thời gian để theo dõi. Đây là một chút giải thích để điền vào giữa các dòng.

a (n, m) đại diện cho số cách chọn A sao cho A [i] = A [i + 1] m lần. Công thức cho a (n, m) tương đương với a (n, m) = {2 * (n chọn m) cho bước chẵn; 0 cho số lẻ lẻ.} Chỉ cho phép một chẵn lẻ vì A [i]! = A [i + 1] phải xảy ra số lần chẵn để A [0] = A [n]. Hệ số của 2 là do lựa chọn ban đầu A [0] = 1 hoặc A [0] = -1.

Khi số lượng (A [i]! = A [i + 1]) được cố định là q (được đặt tên theo công thức c (n)), nó sẽ tách thành hai bước ngẫu nhiên 1D có độ dài q và nq. b (m) là số cách để thực hiện bước đi ngẫu nhiên một chiều của các bước kết thúc tại cùng một nơi mà nó bắt đầu và có 25% cơ hội di chuyển sang trái, 50% cơ hội ở yên và 25% cơ hội di chuyển đúng. Một cách rõ ràng hơn để nêu chức năng tạo là [x ^ m] (1 + 2x + x ^ 2) ^ n, trong đó 1, 2x và x ^ 2 tương ứng là trái, không di chuyển và phải. Nhưng sau đó 1 + 2x + x ^ 2 = (x + 1) ^ 2.


Còn một lý do nữa để yêu PPCG! Cảm ơn bạn.

2

C ++

Chỉ là một cổng của câu trả lời Python (xuất sắc) của Mitch Schwartz. Sự khác biệt chính là tôi đã sử dụng 2để đại diện -1cho abiến và đã làm một cái gì đó tương tự b, cho phép tôi sử dụng một mảng. Sử dụng Intel C ++ với -O3, tôi đã nhận N=141! Phiên bản đầu tiên của tôi có N=140.

Cái này sử dụng Boost. Tôi đã thử một phiên bản song song nhưng gặp một số rắc rối.

#include <boost/multiprecision/gmp.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/rational.hpp>
#include <boost/chrono.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <utility>
#include <map>

typedef boost::multiprecision::mpz_int integer;
typedef boost::array<boost::array<std::map<int, std::map<int, integer> >, 3>, 2> array;
typedef boost::rational<integer> rational;

int main() {
    BOOST_AUTO(T, boost::chrono::high_resolution_clock::now());

    int N = 1;
    integer n = 1;
    array* Y = new array, *X = NULL;
    (*Y)[1][0][0][0] = 1;
    (*Y)[1][1][1][0] = 1;

    while (boost::chrono::high_resolution_clock::now() < T+boost::chrono::seconds(10)) {
        std::cout << N << " " << rational(n, boost::multiprecision::pow(integer(8), N)/4) << std::endl;
        ++N;
        delete X;
        X = Y;
        Y = new array;
        n = 0;

        for (int a=0; a<2; ++a)
            for (int b=0; b<3; ++b)
                for (BOOST_AUTO(s, (*X)[a][b].begin()); s != (*X)[a][b].end(); ++s)
                    for (BOOST_AUTO(t, s->second.begin()); t != s->second.end(); ++t) {
                        integer c = t->second;
                        int d = b&2 ? -1 : b, e = a == 0 ? -1 : a;

                        if (s->first == -1 && t->first+d+e == 0) n += c;
                        (*Y)[a][1][s->first+1][t->first+d] += c;

                        if (s->first == 1 && t->first-d+e == 0) n += c;
                        (*Y)[a][1][s->first-1][t->first-d] += c;

                        if (s->first == 1 && t->first+d-e == 0) n += c;
                        (*Y)[a][2][s->first-1][t->first+d] += c;

                        if (s->first == -1 && t->first-d-e == 0) n += c;
                        (*Y)[a][2][s->first+1][t->first-d] += c;

                        c *= 2;

                        if (s->first == 0 && t->first+d == 0) n += c;
                        (*Y)[a][0][s->first][t->first+d] += c;

                        if (s->first == 0 && t->first-d == 0) n += c;
                        (*Y)[a][0][s->first][t->first-d] += c;
                    }
    }

    delete X;
    delete Y;
}

Điều này cần g++ -O3 kirbyfan64sos.cpp -o kirbyfan64sos -lboost_system -lboost_timer -lboost_chrono -lrt -lgmpphải biên dịch. (Cảm ơn aditsu.)
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.