Формула запрашивается. К сожалению, ситуация настолько сложна, что кажется, что любая формула будет просто окольным способом перечисления всех возможностей. Вместо этого этот ответ предлагает алгоритм, который (а) эквивалентен формуле, включающей суммы произведений биномиальных коэффициентов, и (б) может быть перенесен на многие платформы.
Чтобы получить такую формулу, разбейте возможности на взаимно непересекающиеся группы двумя способами: в зависимости от того, сколько букв в слове выбрано не в слове (пусть это будет ), и в зависимости от того, сколько подстановочных знаков (пробелов) выбрано ( пусть это будет ш ). Если в стойке имеется r = 7 плиток, N доступных плиток, M доступных плиток с буквами, не входящими в слово, и W = 2 доступных пробела, число возможных вариантов выбора, заданных ( m , w ), равноmwr=7NMW=2(m,w)
( Мм) ( Wвес) ( N- М- Wr - m - w)
потому что выбор несловесных букв, пробелов и словесных букв не зависит от ( м , ш , г ) .
Это сводит задачу к нахождению числа способов пишутся словом при выборе только из плиток , представляющих буквы этого слова, учитывая , что имеются заготовки и т - м - ж плитки будут выбраны. Ситуация грязная, и нет закрытой формулы, кажется, доступны. Например, с w = 0 пробелами и m = 3 буквами вне слова остается ровно четыре буквы, оставляющие заклинание «boot», которые были нарисованы из тайлов «b», «o» и «t» , Учитывая, что есть 2 "b", 8 "o" и 6весr - m - ww = 0м = 3286"t" в наборе плиток Scrabble, есть положительные вероятности рисования (мультимножества) "bboo", "bbot", "bbtt", "booo", "boot", "bot", "bttt", "oooo "," ooot "," oott "," ottt "и" tttt ", но только одно из этих заклинаний" boot ". И это был легкий случай! Например, если предположить, что стойка содержит пять плиток, выбранных случайным образом из плиток «o», «b» и «t», вместе с обоими пробелами, существует еще много способов написания слова «загрузочный», а не его написания. Например, «boot» может быть написано из «__boott» и «__bbttt», но не из «__ttttt».
Этот подсчет - суть проблемы - может быть обработан рекурсивно. Я опишу это на примере. Предположим, что мы хотим подсчитать способы написания слова «boot» с одной пустой и еще четырьмя плитками из коллекции плиток «b», «o» и «t» (откуда оставшиеся две плитки показывают непустые буквы не в { "б", "о", "т"}). Рассмотрим первую букву «б»:
«B» можно нарисовать в доступны пути из двух «b» плиток. Это сводит проблему к подсчету количества способов написания суффикса "oot" с использованием обоих пробелов и еще трех плиток из коллекции плиток "o" и "t".( 21)
Один пробел может быть обозначен как «б». Это сводит проблему к подсчету количества способов написания «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 . Вот где биномиальные коэффициенты ( Ммвес и ( ш( Мм) вычисляются и умножаются.( 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 ,