Формула запитується. На жаль, ситуація є настільки складною, здається, що будь-яка формула буде просто обхідним способом перерахування всіх можливостей. Натомість у цій відповіді пропонується алгоритм, який (а) рівносильний формулі, що включає суми добутків двочленних коефіцієнтів і (b) може бути перенесений на багато платформ.
Щоб отримати таку формулу, розділіть можливості на групи, що перебувають у взаємозв'язку, двома способами: відповідно до того, скільки літер не в цьому слові вибрано у стійці (нехай це буде ) та відповідно до того, скільки обраних марок (пробілів) вибрано ( нехай це буде ш ). Коли в стійці r = 7 плиток, N доступних плиток, M доступних плиток з літерами не в слові, і W = 2 пробіли, кількість можливих варіантів, заданих ( m , w ), становитьmwr=7NMW=2(m,w)
( Мм) ( Шш) ( N- М- Шr - m - w)
тому що вибір несловних букв, пробілів та букв слова незалежно залежать від ( м , ш , г ) .
Це зменшує проблему пошуку кількості способів написання слова під час вибору лише з плиток, що представляють літери слова, враховуючи, що наявні пробіли та вибрано плитки r - m - w . Ситуація безладна, і закрита формула не здається доступною. Наприклад, з w = 0 пробілами та m = 3 непотрібні букви намальовано, залишиться точно чотири літери для написання "завантаження", які були намальовані з плиток "b", "o" та "t" . Враховуючи, що є 2 "b", 8 "o" 'і 6шr - m - ww = 0m = 3286"Набір" у наборі плиток Scrabble, є позитивні ймовірності малювання (мультисети) "bboo", "bbot", "bbtt", "booo", "boot", "bou", "bttt", "oooo "," ooot "," oott "," ottt "та" tttt ", але лише одне з цих заклинань" boot ". І це був простий випадок! Наприклад, якщо припустити, що стійка містить п’ять плиток, вибраних випадковим чином з плиток "o", "b" та "t", разом з обома заготовками існує ще багато способів написання "boot" - а не написання. Наприклад, "boot" може бути написано з "__boott" і "__bbttt", але не з "__ttttt".
Цей підрахунок - суть проблеми - може бути вирішений рекурсивно. Я опишу це на прикладі. Припустимо, ми хочемо порахувати способи написання "завантаження" однією порожньою та ще чотирма плитками із колекції плиток "b", "o" та "t" (звідки на двох інших плитках відображаються непорожні літери не в { "b", "o", "t"}). Розглянемо першу букву "b":
В ( 2) можна намалювати "b" способи з двох наявних плиток "b". Це зводить проблему до підрахунку кількості способів написання суфіксу "oot", використовуючи як пробіли, так і ще три плитки із колекції плиток "o" та "t".( 21)
Один пробіл може бути позначений як "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))
}
Інтерфейс цієї функції вказує стандартну плитку Scrabble, перетворює задане слово в його мультисетову структуру даних і виконує подвійну суму над і w . Ось де біноміальні коефіцієнти ( Ммш і ( Ш( Мм) обчислюються та множуються.( Шш)
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 , отриману в моєму іншому відповіді (який використовує подібний метод , але кушетки його в більш потужних рамках вимагають символічну алгебри обчислювальної платформу). Ймовірності всіх чотирьох слів досить близькі до симуляції Баас (які не могли б очікувати , щоб дати точне значення «зоологія» в зв'язку з його низькою ймовірністю 11840 / 16007560800 , що менше , ніж один на мільйон).114327888 / 160075608002381831 / 33349085011840 / 16007560800 ,