Đây là một khái quát của Vấn đề sinh nhật nổi tiếng : được cá nhân có "sinh nhật" được phân phối đồng đều, ngẫu nhiên trong số các tập hợp , khả năng không có sinh nhật nào được chia sẻ bởi hơn cá nhân?d = 6 m = 20n=100d=6m=20
Một phép tính chính xác mang lại câu trả lời (để tăng gấp đôi độ chính xác). Tôi sẽ phác thảo lý thuyết và cung cấp mã cho Thời gian tiệm cận mã là mà làm cho nó phù hợp với số lượng rất lớn các sinh nhật và cung cấp hiệu suất hợp lý cho đến khi là trong hàng ngàn. Tại thời điểm đó, phép tính gần đúng Poisson đã thảo luận tại Mở rộng nghịch lý sinh nhật cho hơn 2 người nên hoạt động tốt trong hầu hết các trường hợp.n , m , d . O ( n 2 log ( d ) ) d n0.267747907805267n,m,d.O(n2log(d))dn
Giải thích về giải pháp
Hàm tạo xác suất (pgf) cho kết quả của cuộn độc lập của một khuôn mặt làdnd
d−nfn(x1,x2,…,xd)=d−n(x1+x2+⋯+xd)n.
Hệ số của trong việc mở rộng đa thức này đưa ra số cách mà khuôn mặt có thể xuất hiện chính xác lần , i đ i i = 1 , 2 , ... , d .xe11xe22⋯xeddieii=1,2,…,d.
Giới hạn sự quan tâm của chúng tôi không quá xuất hiện bởi bất kỳ khuôn mặt nào tương đương với việc đánh giá modulo lý tưởng tạo bởi Để thực hiện đánh giá này, hãy sử dụng Định lý nhị thức để thu đượcf n I x m + 1 1 , x m + 1 2 , Mạnh , x m + 1 d .mfnIxm+11,xm+12,…,xm+1d.
fn(x1,…,xd)=((x1+⋯+xr)+(xr+1+xr+2+⋯+x2r))n=∑k=0n(nk)(x1+⋯+xr)k(xr+1+⋯+x2r)n−k=∑k=0n(nk)fk(x1,…,xr)fn−k(xr+1,…,x2r)
khi là chẵn. Viết ( thuật ngữ ), chúng tôi cód=2rf(d)n=fn(1,1,…,1)d
f(2r)n=∑k=0n(nk)f(r)kf(r)n−k.(a)
Khi là số lẻ, hãy sử dụng phân tách tương tựd=2r+1
fn(x1,…,xd)=((x1+⋯+x2r)+x2r+1)n=∑k=0n(nk)fk(x1,…,x2r)fn−k(x2r+1),
cho
f(2r+1)n=∑k=0n(nk)f(2r)kf(1)n−k.(b)
Trong cả hai trường hợp, chúng tôi cũng có thể giảm mọi thứ modulo , dễ dàng thực hiện bắt đầu bằngI
fn(xj)≅{xn0n≤mn>mmodI,
cung cấp các giá trị khởi đầu cho đệ quy,
f(1)n={10n≤mn>m
Điều làm cho hiệu quả này là bằng cách chia các biến thành hai nhóm có kích thước bằng nhau mỗi biến và đặt tất cả các giá trị biến thành chúng ta chỉ phải đánh giá mọi thứ một lần cho một nhóm và sau đó kết hợp các kết quả. Điều này đòi hỏi phải tính toán tối đa thuật ngữ, mỗi thuật ngữ cần tính toán cho sự kết hợp. Chúng tôi thậm chí không cần một mảng 2D để lưu trữ , bởi vì khi tính toán chỉ và .dr1,n+1O(n)f(r)nf(d)n,f(r)nf(1)n
Tổng số bước là một ít hơn số chữ số trong khai triển nhị phân của (tính các phần tách thành các nhóm bằng nhau trong công thức ) cộng với số lượng trong phần mở rộng (tính tất cả các lần lẻ giá trị gặp phải, yêu cầu áp dụng công thức ). Đó vẫn chỉ là các bước .d(a)(b)O(log(d))
Trong R
một máy trạm cũ hàng thập kỷ, công việc được thực hiện trong 0,007 giây. Mã được liệt kê ở cuối bài này. Nó sử dụng logarit của xác suất, thay vì chính xác suất, để tránh tràn ra ngoài hoặc tích lũy quá nhiều dòng chảy. Điều này cho phép loại bỏ yếu tố trong giải pháp để chúng tôi có thể tính toán các số liệu làm cơ sở cho xác suất.d−n
Lưu ý rằng quy trình này dẫn đến việc tính toán toàn bộ chuỗi xác suất cùng một lúc, điều này dễ dàng cho phép chúng tôi nghiên cứu cách cơ hội thay đổi với .f0,f1,…,fnn
Các ứng dụng
Phân phối trong Bài toán sinh nhật tổng quát được tính theo hàm tmultinom.full
. Thách thức duy nhất nằm ở việc tìm ra giới hạn trên cho số lượng người phải có mặt trước khi cơ hội của tỷ lệ trở nên quá lớn. Đoạn mã sau thực hiện điều này bằng sức mạnh vũ phu, bắt đầu bằng nhỏ và nhân đôi cho đến khi nó đủ lớn. Do đó, toàn bộ tính toán mất thời gian trong đó là giải pháp. Toàn bộ phân phối xác suất cho số người lên đến được tính toán.m+1nO(n2log(n)log(d))nn
#
# The birthday problem: find the number of people where the chance of
# a collision of `m+1` birthdays first exceeds `alpha`.
#
birthday <- function(m=1, d=365, alpha=0.50) {
n <- 8
while((p <- tmultinom.full(n, m, d))[n] > alpha) n <- n * 2
return(p)
}
Ví dụ, số người tối thiểu cần thiết trong một đám đông để làm cho nhiều khả năng hơn là ít nhất tám người trong số họ chia sẻ một sinh nhật là , như tính toán tìm thấy . Chỉ mất vài giây. Đây là một phần của một phần của đầu ra:798birthday(7)
Một phiên bản đặc biệt của vấn đề này được đề cập tại Mở rộng nghịch lý sinh nhật cho hơn 2 người , liên quan đến trường hợp một cái chết mặt được cuộn rất nhiều lần.365
Mã
# Compute the chance that in `n` independent rolls of a `d`-sided die,
# no side appears more than `m` times.
#
tmultinom <- function(n, m, d, count=FALSE) tmultinom.full(n, m, d, count)[n+1]
#
# Compute the chances that in 0, 1, 2, ..., `n` independent rolls of a
# `d`-sided die, no side appears more than `m` times.
#
tmultinom.full <- function(n, m, d, count=FALSE) {
if (n < 0) return(numeric(0))
one <- rep(1.0, n+1); names(one) <- 0:n
if (d <= 0 || m >= n) return(one)
if(count) log.p <- 0 else log.p <- -log(d)
f <- function(n, m, d) { # The recursive solution
if (d==1) return(one) # Base case
r <- floor(d/2)
x <- double(f(n, m, r), m) # Combine two equal values
if (2*r < d) x <- combine(x, one, m) # Treat odd `d`
return(x)
}
one <- c(log.p*(0:m), rep(-Inf, n-m)) # Reduction modulo x^(m+1)
double <- function(x, m) combine(x, x, m)
combine <- function(x, y, m) { # The Binomial Theorem
z <- sapply(1:length(x), function(n) { # Need all powers 0..n
z <- x[1:n] + lchoose(n-1, 1:n-1) + y[n:1]
z.max <- max(z)
log(sum(exp(z - z.max), na.rm=TRUE)) + z.max
})
return(z)
}
x <- exp(f(n, m, d)); names(x) <- 0:n
return(x)
}
Câu trả lời có được với
print(tmultinom(100,20,6), digits=15)
0.267747907805267