นี่เป็นลักษณะทั่วไปของปัญหาวันเกิดที่มีชื่อเสียง: ให้บุคคลที่มีการกระจาย "วันเกิด" แบบสุ่มอย่างสม่ำเสมอในกลุ่มชุดของความเป็นไปได้อะไรคือโอกาสที่ไม่มีวันเกิดร่วมกันมากกว่าคน?d = 6 m = 20n = 100d= 6m = 20
การคำนวณที่แน่นอนให้ผลลัพธ์คำตอบ (เพื่อความแม่นยำสองเท่า) ฉันจะร่างทฤษฎีและให้รหัสสำหรับทั่วไป เวลาของซีมโทติคของรหัสคือซึ่งทำให้เหมาะสำหรับวันเกิดจำนวนมากและให้ประสิทธิภาพที่สมเหตุสมผลจนกระทั่งอยู่ในหลักพัน ณ จุดนั้นการประมาณปัวซงกล่าวถึงในการขยายเส้นขนานวันเกิดให้มากกว่า 2 คนควรจะทำงานได้ดีในกรณีส่วนใหญ่n , m , d . O ( n 2บันทึก( d ) ) d n0.267747907805267n , m , d.O ( n2เข้าสู่ระบบ( d) )dn
คำอธิบายของการแก้ปัญหา
ฟังก์ชันสร้างความน่าจะเป็น (pgf) สำหรับผลลัพธ์ของการหมุนรอบอิสระของการตายด้านคือวันnd
d- nฉn( x1, x2, … , xd) = d- n( x1+ x2+ ⋯ + xd)n.
ค่าสัมประสิทธิ์ของในการขยายตัวของพหุนามนี้จะช่วยให้หลายวิธีในการที่ต้องเผชิญกับสามารถปรากฏตรงครั้งฉันอีฉันฉัน= 1 , 2 , ... , dxอี11xอี22⋯ xอีddผมอีผมi = 1 , 2 , … , d.
การจำกัดความสนใจของเราไม่เกินใบหน้าใด ๆ ก็เท่ากับการประเมิน modulo อุดมคติสร้างโดย ในการประเมินผลนี้ใช้ทฤษฎีบททวินาม (Binomial Theorem) ซ้ำ ๆ เพื่อรับฉn ผมx เมตร+ 1 1 , x เมตร+ 1 2 , ... , x เมตร+ 1 dม.ฉnผมxm + 11, xm + 12, … , xm + 1d.
ฉn( x1, … , xd)= ( ( x1+ ⋯ + xR) + ( xr + 1+ xr + 2+ ⋯ + x2 ร) )n= ∑k = 0n( nk) (x1+ ⋯ + xR)k( xr + 1+ ⋯ + x2 ร)n - k= ∑k = 0n( nk) fk( x1, … , xR) fn - k( xr + 1, … , x2 ร)
เมื่อเป็นคู่ กำลังเขียน ( คำศัพท์ ) เรามีf ( d ) n = f n ( 1 , 1 , … , 1 ) dd= 2 rฉ( d)n= fn( 1 , 1 , … , 1 )d
ฉ( 2 r )n= ∑k = 0n( nk) f( r )kฉ( r )n - k.(ก)
เมื่อเป็นเลขคี่ให้ใช้การแยกแบบอะนาล็อกd= 2 r + 1
ฉn( x1, … , xd)= ( ( x1+ ⋯ + x2 ร) + x2 r + 1)n= ∑k = 0n( nk) fk( x1, … , x2 ร) fn - k( x2 r + 1) ,
ให้
ฉ( 2 r + 1 )n= ∑k = 0n( nk) f( 2 r )kฉ( 1 )n - k.(ข)
ในทั้งสองกรณีเราอาจลดทุกอย่างแบบโมดูโลซึ่งเริ่มต้นได้ง่ายด้วยผม
ฉn( xJ) ≅{ xn0n ≤ mn > mพอควรผม,
ให้ค่าเริ่มต้นสำหรับการสอบถามซ้ำ
ฉ( 1 )n= { 10n ≤ mn > m
สิ่งที่ทำให้สิ่งนี้มีประสิทธิภาพคือการแบ่งตัวแปรออกเป็นสองกลุ่มที่มีขนาดเท่ากันของตัวแปรแต่ละตัวและตั้งค่าตัวแปรทั้งหมดเป็นเราจะต้องประเมินทุกอย่างเพียงครั้งเดียวสำหรับกลุ่มเดียวแล้วรวมผลลัพธ์ สิ่งนี้ต้องใช้การคำนวณสูงสุดคำแต่ละคำต้องการการคำนวณสำหรับชุดค่าผสม เราไม่จำเป็นต้องใช้อาร์เรย์ 2 มิติในการจัดเก็บเพราะเมื่อคำนวณเฉพาะและเท่านั้นr 1 , n + 1 O ( n ) f ( r ) n f ( d ) n , f ( r ) n f ( 1 ) ndR1 ,n + 1O ( n )ฉ( r )nฉ( d)n,ฉ( r )nฉ( 1 )n
จำนวนขั้นตอนทั้งหมดคือหนึ่งน้อยกว่าจำนวนหลักในการขยายฐานสองของ (ซึ่งนับการแบ่งออกเป็นกลุ่มเท่า ๆ กันในสูตร ) บวกจำนวนครั้งในการขยาย (ซึ่งนับทุกครั้งที่คี่ พบค่าต้องการแอปพลิเคชันของสูตร ) นั่นเป็นเพียงขั้นตอน( a ) ( b ) O ( บันทึก( d ) )d( a )( b )O ( บันทึก( d) )
ในR
เวิร์กสเตชันอายุสิบปีงานเสร็จใน 0.007 วินาที รหัสมีการระบุไว้ในตอนท้ายของโพสต์นี้ มันใช้ลอการิทึมของความน่าจะเป็นมากกว่าความน่าจะเป็นของตัวเองเพื่อหลีกเลี่ยงการล้นหรือการสะสมอันเดอร์โฟล์ที่มากเกินไป สิ่งนี้ทำให้สามารถลบปัจจัยในโซลูชันดังนั้นเราอาจคำนวณจำนวนที่เป็นไปได้d- n
หมายเหตุว่านี้ผลการขั้นตอนในการใช้คอมพิวเตอร์ทั้งลำดับของความน่าจะในครั้งเดียวซึ่งได้อย่างง่ายดายช่วยให้เราสามารถศึกษาวิธีโอกาสเปลี่ยนกับn nฉ0, F1, … , fnn
การประยุกต์ใช้งาน
tmultinom.full
การกระจายตัวในวันเกิดปัญหาทั่วไปคำนวณโดยฟังก์ชั่น ความท้าทายเพียงอย่างเดียวคือการหาขอบเขตบนของจำนวนคนที่ต้องอยู่ก่อนที่โอกาสของ -collision จะยิ่งใหญ่เกินไป รหัสต่อไปนี้ทำได้โดยใช้กำลังดุร้ายเริ่มต้นด้วยเล็ก ๆและเพิ่มเป็นสองเท่าจนกระทั่งมันใหญ่พอ การคำนวณทั้งหมดจึงใช้เวลาเวลาที่เป็นคำตอบ การคำนวณการแจกแจงความน่าจะเป็นทั้งหมดสำหรับจำนวนผู้ใช้จนถึงคำนวณได้n O ( n 2บันทึก( n ) บันทึก( d ) ) n nm + 1nO ( n2เข้าสู่ระบบ( n ) บันทึก( 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)
}
ตัวอย่างเช่นจำนวนขั้นต่ำของคนที่จำเป็นในฝูงชนที่จะทำให้มันมีโอกาสมากขึ้นกว่าไม่ได้ว่าอย่างน้อยแปดพวกเขาส่วนวันเกิดเป็นเท่าที่พบโดยการคำนวณ ใช้เวลาเพียงไม่กี่วินาที นี่คือพล็อตของส่วนหนึ่งของผลลัพธ์:798birthday(7)
รุ่นพิเศษของปัญหานี้แก้ไขได้ที่การขยายเส้นขนานของวันเกิดให้มากกว่า 2 คนซึ่งเกี่ยวข้องกับกรณีของผู้ตายด้านที่มีจำนวนครั้งมาก365
รหัส
# 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)
}
คำตอบที่ได้รับด้วย
print(tmultinom(100,20,6), digits=15)
0.267747907805267