สูตรที่มีการร้องขอ แต่น่าเสียดายที่สถานการณ์มีความซับซ้อนมากจนดูเหมือนว่าสูตรใด ๆ จะเป็นเพียงวงเวียนในการแจกแจงความเป็นไปได้ทั้งหมด แต่คำตอบนี้นำเสนออัลกอริทึมซึ่งเป็น (a) tantamount สำหรับสูตรที่เกี่ยวข้องกับผลรวมของผลิตภัณฑ์ของสัมประสิทธิ์ทวินามและ (b) สามารถนำไปใช้กับหลายแพลตฟอร์มได้
เพื่อให้ได้สูตรดังกล่าวแบ่งความเป็นไปได้ออกเป็นกลุ่มที่แยกจากกันในสองวิธี: ตามจำนวนตัวอักษรที่ไม่ได้อยู่ในคำที่ถูกเลือกในชั้นวาง (ให้เป็นm ) และตามจำนวน wildcard (ช่องว่าง) ที่เลือก ( ปล่อยให้มันเป็นw ) เมื่อมีไพ่r=7ในชั้นวางไพ่ที่มีอยู่Nแผ่นMมีตัวอักษรไม่อยู่ในคำและมีช่องว่างW=2จำนวนตัวเลือกที่เป็นไปได้ที่กำหนดโดย(m,w)คือ
(Mm)(Ww)(N−M−Wr−m−w)
เพราะทางเลือกของตัวอักษรที่ไม่ใช่คำช่องว่างและตัวอักษรคำว่าเงื่อนไขเป็นอิสระเกี่ยวกับ(m,w,r).
ซึ่งจะช่วยลดปัญหาในการหาจำนวนวิธีที่จะสะกดคำเมื่อมีการเลือกเฉพาะจากกระเบื้องที่เป็นตัวแทนของตัวอักษรของคำที่ กำหนดว่าwช่องว่างที่มีอยู่และr−m−wกระเบื้องจะถูกเลือก สถานการณ์ยุ่งเหยิงและไม่มีสูตรปิดให้บริการ ตัวอย่างเช่นเมื่อw=0ว่างและm=3ตัวอักษรที่ไม่อยู่ในคำนั้นจะมีตัวอักษรเหลืออยู่สี่ตัวที่จะสะกด "boot" ที่ถูกดึงมาจากไทล์ "b", "o" และ "t" . เนื่องจากมี2 "b" คือ8 "o" และ6"t" ในชุดไพ่ Scrabble มีความน่าจะเป็นในเชิงบวกของการวาด (หลายชุด) "bboo", "bbot", "bbtt", "booo", "บูต", "ขวด", "bttt", "oooo" "," ooot "," oott "," ottt "และ" tttt "แต่มีเพียงหนึ่งในคาถา" บูต "เหล่านี้ และนั่นเป็นกรณีที่ง่าย! ตัวอย่างเช่นสมมติว่าชั้นวางมีห้าแผ่นที่เลือกแบบสุ่มจากแผ่น "o", "b" และ "t" พร้อมด้วยช่องว่างทั้งสองมีหลายวิธีในการสะกด "บูต" - และไม่ต้องสะกด ตัวอย่างเช่น "boot" สามารถสะกดได้จาก "__boott" และ "__bbttt" แต่ไม่ใช่จาก "__ttttt"
การนับนี้ - หัวใจของปัญหา - สามารถจัดการซ้ำได้ ฉันจะอธิบายด้วยตัวอย่าง สมมติว่าเราต้องการนับวิธีการสะกดคำว่า "บูต" ด้วยหนึ่งช่องว่างและอีกสี่แผ่นจากการรวบรวมแผ่น "b", "o" และ "t" (ที่เหลืออีกสองแผ่นแสดงตัวอักษรที่ไม่ใช่ช่องว่างที่ไม่ใช่ใน { "b", "o", "t"}) พิจารณาตัวอักษรตัวแรก "b":
สามารถวาด "b" ใน(21)วิธีจากแผ่น "b" สองรายการที่มีอยู่ สิ่งนี้จะช่วยลดปัญหาในการนับจำนวนวิธีสะกดคำต่อท้าย "oot" โดยใช้ช่องว่างและอีกสามแผ่นจากการรวบรวมไทล์ "o" และ "t"
หนึ่งช่องว่างสามารถกำหนดเป็น "b" สิ่งนี้จะช่วยลดปัญหาในการนับจำนวนวิธีการสะกด "oot" โดยใช้ช่องว่างที่เหลือและเพียงสามแผ่นจากคอลเล็กชันของแผ่น "o" และ "t"
โดยทั่วไปขั้นตอน (1) และ (2) - ซึ่งแยกจากกันและดังนั้นจึงมีส่วนเพิ่มในการคำนวณความน่าจะเป็น - สามารถนำมาใช้เป็นวนรอบจำนวนช่องว่างที่อาจเป็นไปได้สำหรับตัวอักษรตัวแรก ปัญหาที่ลดลงได้รับการแก้ไขซ้ำแล้วซ้ำอีก กรณีฐานเกิดขึ้นเมื่อมีตัวอักษรหนึ่งตัวเหลืออยู่มีจำนวนไพ่ที่มีตัวอักษรนั้นอยู่จำนวนหนึ่งและอาจมีช่องว่างในชั้นวางด้วยเช่นกัน เราต้องตรวจสอบให้แน่ใจว่าจำนวนช่องว่างในชั้นวางรวมถึงจำนวนช่องว่างที่มีจะเพียงพอที่จะได้รับปริมาณที่ต้องการของตัวอักษรตัวสุดท้าย
นี่คือR
รหัสสำหรับขั้นตอนแบบเรียกซ้ำ rack
มักจะเท่ากับ , เป็นอาร์เรย์ของการนับของตัวอักษร (เช่น) เป็นโครงสร้างที่คล้ายกันให้หมายเลขของกระเบื้องที่มีอยู่กับตัวอักษรเหล่านั้นและคือจำนวนของช่องว่างสันนิษฐานว่าจะเกิดขึ้นในชั้น7word
c(b=1, o=2, t=1)
alphabet
wild
f <- function(rack, word, alphabet, wild) {
if (length(word) == 1) {
return(ifelse(word > rack+wild, 0, choose(alphabet, rack)))
}
n <- word[1]
if (n <= 0) return(0)
m <- alphabet[1]
x <- sapply(max(0, n-wild):min(m, rack),
function(i) {
choose(m, i) * f(rack-i, word[-1], alphabet[-1], wild-max(0, n-i))
})
return(sum(x))
}
อินเตอร์เฟซที่ฟังก์ชั่นนี้ระบุกระเบื้องข่วนมาตรฐานแปลงคำที่กำหนดในโครงสร้างข้อมูล MultiSet และดำเนินการรวมสองครั้งกว่าและกว้าง นี่เป็นที่ที่ค่าสัมประสิทธิ์ทวินาม( Mmwและ ( W(Mm)คำนวณและคูณ(Ww)
scrabble <- function(sword, n.wild=2, rack=7,
alphabet=c(a=9,b=2,c=2,d=4,e=12,f=2,g=3,h=2,i=9,j=1,k=1,l=4,m=2,
n=6,o=8,p=2,q=1,r=6,s=4,t=6,u=4,v=2,w=2,x=1,y=2,z=1),
N=sum(alphabet)+n.wild) {
word = sort(table(strsplit(sword, NULL))) # Sorting speeds things a little
a <- sapply(names(word), function(s) alphabet[s])
names(a) <- names(word)
x <- sapply(0:n.wild, function(w) {
sapply(sum(word):rack-w,
function(i) {
f(i, word, a, wild=w) *
choose(n.wild, w) * choose(N-n.wild-sum(a), rack-w-i)
})
})
return(list(numerator = sum(x), denominator = choose(N, rack),
value=sum(x) / choose(N, rack)))
}
ลองใช้วิธีแก้ปัญหานี้และเวลาที่เราไป การทดสอบต่อไปนี้ใช้อินพุตเดียวกันกับที่ใช้ในการจำลองโดย @Rasmus Bååth :
system.time(x <- sapply(c("boot", "red", "axe", "zoology"), scrabble))
เครื่องนี้รายงานเวลาที่ผ่านไปทั้งหมดวินาที: รวดเร็วพอสมควร ผลลัพธ์หรือไม่0.05
> x
boot red axe zoology
numerator 114327888 1249373480 823897928 11840
denominator 16007560800 16007560800 16007560800 16007560800
value 0.007142118 0.07804896 0.0514693 7.396505e-07
ความน่าจะเป็นสำหรับ "บูต" ของตรงเท่ากับค่า2381831 / 333490850ได้รับในคำตอบอื่น ๆ ของฉัน (ซึ่งใช้วิธีการคล้ายกัน แต่เตียงนอนมันอยู่ในกรอบที่กำหนดให้มีประสิทธิภาพมากขึ้นพีชคณิตสัญลักษณ์แพลตฟอร์มคอมพิวเตอร์) ความน่าจะเป็นสำหรับทุกสี่คำจะได้อยู่ใกล้จำลอง Baath (ซึ่งไม่สามารถคาดหวังว่าจะให้ค่าที่ถูกต้องสำหรับ "สัตววิทยา" เนื่องจากความน่าจะเป็นที่ต่ำของ11840 / 16007560800 ,ซึ่งน้อยกว่าหนึ่งในล้าน)114327888/160075608002381831/33349085011840/16007560800,