수식 요구된다. 불행히도 상황은 너무 복잡하여 모든 수식이 모든 가능성을 열거하는 원형 길 일뿐입니다. 대신에,이 답변은 (a) 이항 계수의 곱의 합을 포함하는 공식에 탄탈 가능하고 (b) 많은 플랫폼으로 이식 될 수 있는 알고리즘 을 제공합니다 .
이러한 공식을 얻으려면 두 가지 방법으로 가능성을 서로 분리 된 그룹으로 분류 하십시오. 랙에서 단어에 포함 되지 않은 문자 수에 따라 (이것은 ), 선택한 와일드 카드 (공백) 수에 따라 ( 이것이 w ). 이 때 , R = 7 개 랙 타일 N 가능한 타일 M 없는 단어의 글자와 타일 가능하고, W = 2 사용할 블랭크, 주어진 가능한 선택의 수 ( m은 , 승 ) 이고mwr=7NMW=2(m,w)
(Mm)(Ww)(N−M−Wr−m−w)
비 단어 문자, 공백 및 단어 문자의 선택은 ( m , w , r ) 에 독립적 인 조건부이기 때문에 .(m,w,r).
이 단어의 문자를 나타내는 타일에서만 선택할 때 단어를 철자하는 방법의 수를 찾는 문제를 감소 주어진 것을 공백을 사용할 수 있으며, 타일이 선택됩니다. 상황이 지저분하고 닫힌 공식이 없습니다. 예를 들어, 공백과 단어를 벗어난 문자가 그려지면 "b", "o"및 "t"타일에서 가져온 "부팅"을 철자하기 위해 정확히 4 개의 문자가 남습니다. . 감안있다 '의 "B" 의 "O"'및wr−m−ww=0m=3286"t"는 글자 맞추기 타일 세트에 있으며, 그림 (멀티 세트) "bboo", "bbot", "bbtt", "booo", "boot", "bott", "bttt", "oooo의 긍정적 확률이 있습니다. ","ooot ","oott ","ottt "및"tttt "이지만이 중 하나만"부팅 "입니다. 그리고 그것은 쉬운 경우였습니다! 예를 들어, 랙에 "o", "b"및 "t"타일에서 무작위로 선택된 5 개의 타일이 있고 두 공백과 함께 "부팅"을 철자가 아닌 철자가 많은 방법이 있다고 가정합니다. 예를 들어 "boot"는 "__boott"및 "__bbttt"에서 철자를 입력 할 수 있지만 "__ttttt"는 철자를 지정할 수 없습니다.
문제의 핵심 인이 계산은 재귀 적으로 처리 될 수 있습니다. 예를 들어 설명하겠습니다. "b", "o"및 "t"타일 모음에서 하나의 공백과 4 개의 타일을 사용하여 "부팅"철자법을 세고 싶다고 가정합니다 (나머지 두 타일은 { "b", "o", "t"}). 첫 글자 "b"를 보자.
"b"는 사용 가능한 두 개의 "b"타일 에서 방식 으로 그릴 수 있습니다. 이렇게하면 공백과 "o"및 "t"타일 모음에서 세 개의 타일 만 사용하여 접미사 "oot"를 철자하는 방법의 수를 계산하는 문제가 줄어 듭니다.(21)
하나의 공백을 "b"로 지정할 수 있습니다. 이렇게하면 나머지 공백과 "o"및 "t"타일 모음에서 3 개 이상의 타일을 사용하여 "oot"철자를 쓰는 방법의 수를 계산하는 문제가 줄어 듭니다.
일반적으로 (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 타일을 지정하고 주어진 단어를 다중 집합 데이터 구조로 변환하고 과 대해 이중 합을 수행합니다 . 이항 계수 및 이 계산되고 곱해지는 위치입니다.mw(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
"부팅"확률 은 필자의 다른 답변 에서 얻은 의 값과 정확히 같습니다 (유사한 방법을 사용하지만 상징적 인 대수 컴퓨팅 플랫폼을 요구하는 더 강력한 프레임 워크에 포함). 네 단어에 대한 확률 (때문에 자사의 낮은 확률로 '동물학 "에 대한 정확한 값을 제공 할 것으로 예상 할 수없는 합리적으로 가까운 바트의 시뮬레이션에 있습니다 덜 만에 하나보다).114327888/160075608002381831/33349085011840/16007560800,