È richiesta una formula Sfortunatamente, la situazione è così complicata che sembra che qualsiasi formula sarà semplicemente un modo indiretto di elencare tutte le possibilità. Invece, questa risposta offre un algoritmo che è (a) equivalente a una formula che coinvolge somme di prodotti con coefficienti binomiali e (b) può essere portato su molte piattaforme.
Per ottenere una formula del genere, suddividere le possibilità in gruppi reciprocamente disgiunti in due modi: in base a quante lettere non presenti nella parola sono selezionate nel rack (lasciare che sia ) e in base a quanti caratteri jolly (spazi) sono selezionati ( lascia che sia w ). Quando ci sono r = 7 tessere nel rack, N tessere disponibili, M tessere disponibili con lettere non nella parola e W = 2 spazi vuoti disponibili, il numero di possibili scelte fornite da ( m , w ) èmwr=7NMW=2(m,w)
(Mm)(Ww)(N−M−Wr−m−w)
perché le scelte di lettere non vuote, spazi vuoti e lettere di parole sono condizionate indipendentemente da (m,w,r).
Questo riduce il problema di trovare il numero di modi per scrivere una parola quando si seleziona solo dalle piastrelle che rappresentano le lettere della parola, dato che grezzi sono disponibili e r - m - w piastrelle saranno selezionati. La situazione è disordinata e nessuna formula chiusa sembra disponibile. Ad esempio, con w = 0 spazi vuoti e m = 3 lettere fuori parola verranno disegnate esattamente quattro lettere per scrivere "boot" che sono state disegnate dalle tessere "b", "o" e "t" . Dato che ci sono 2 "b", 8 "o" e 6wr−m−ww=0m=3286"t" è nel set di tessere Scrabble, ci sono probabilità positive di disegno (multiset) "bboo", "bbot", "bbtt", "booo", "boot", "bott", "bttt", "oooo "," ooot "," oott "," ottt "e" tttt ", ma solo uno di questi incantesimi" avvia ". E quello era il caso facile! Ad esempio, supponendo che il rack contenga cinque tessere scelte casualmente dalle tessere "o", "b" e "t", insieme a entrambi gli spazi vuoti, ci sono molti altri modi per scrivere "boot" - e non per compilarlo. Ad esempio, "boot" può essere scritto da "__boott" e "__bbttt", ma non da "__ttttt".
Questo conteggio - il cuore del problema - può essere gestito in modo ricorsivo. Lo descriverò con un esempio. Supponiamo di voler contare i modi di scrivere "boot" con una casella vuota e altre quattro tessere dalla collezione di tessere "b", "o" e "t" (da cui le rimanenti due tessere mostrano lettere non vuote non in { "b", "o", "t"}). Considera la prima lettera, "b":
È possibile disegnare una "b" modi tra le due tessere "b" disponibili. Ciò riduce il problema al conteggio del numero di modi per scrivere il suffisso "oot" usando entrambi gli spazi vuoti e solo altre tre tessere dalla raccolta di tessere "o" e "t".(21)
Un vuoto può essere designato come "b". Ciò riduce il problema al conteggio del numero di modi di scrivere "oot" usando il vuoto rimanente e solo altre tre tessere dalla raccolta di tessere "o" e "t".
In generale, i passaggi (1) e (2) - che sono disgiunti e quindi contribuiscono in modo aggiuntivo ai calcoli della probabilità - possono essere implementati come un ciclo sul possibile numero di spazi che potrebbero essere utilizzati per la prima lettera. Il problema ridotto viene risolto in modo ricorsivo. Il caso base si verifica quando è rimasta una lettera, c'è un certo numero di tessere con quella lettera disponibile e potrebbero esserci anche degli spazi vuoti nel rack. Dobbiamo solo assicurarci che il numero di spazi vuoti nel rack più il numero di tessere disponibili sia sufficiente per ottenere la quantità desiderata di quest'ultima lettera.
Ecco il R
codice per il passaggio ricorsivo. rack
di solito è uguale a , è una matrice di conteggi delle lettere (come ), è una struttura simile che dà il numero di tessere disponibili con quelle lettere, ed è il numero di spazi bianchi che si presume si verifichino nel 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))
}
Un'interfaccia per questa funzione specifica i riquadri Scrabble standard, converte una determinata parola nella sua struttura di dati multiset ed esegue la doppia somma su e w . Qui è dove i coefficienti binomiali ( Mmw e ( W(Mm) sono calcolati e moltiplicati.(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)))
}
Proviamo questa soluzione e cronometriamo mentre procediamo. Il seguente test utilizza gli stessi input impiegati nelle simulazioni di @Rasmus Bååth :
system.time(x <- sapply(c("boot", "red", "axe", "zoology"), scrabble))
Questa macchina registra un tempo totale trascorso di secondi: ragionevolmente veloce. I risultati?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
La probabilità di "boot" di è esattamente uguale al valore 2.381.831 / 333.490.850 ottenuto in mia altra risposta (che utilizza un metodo simile, ma divani in un quadro più potente che richiede una piattaforma di calcolo algebra simbolica). Le probabilità per tutte e quattro le parole sono ragionevolmente vicino alle simulazioni del Baath (che non si poteva pretendere di dare un valore preciso per "zoologia" a causa della sua bassa probabilità di 11840 / 16.007.560 mila ottocento , che è meno di uno su un milione).114327888/160075608002381831/33349085011840/16007560800,