web-dev-qa-db-fra.com

Structure de données pour les dés chargés?

Supposons que j'ai un dé chargé à n côtés où chaque côté k a une certaine probabilité pk de venir quand je le roule. Je suis curieux de savoir s'il existe un bon algorithme pour stocker ces informations statiquement (c'est-à-dire pour un ensemble fixe de probabilités) afin de pouvoir simuler efficacement un lancer aléatoire du dé.

Actuellement, j'ai une solution O (lg n) pour ce problème. L'idée est de stocker un tableau de la probabilité cumulée des premiers k côtés pour tous les k, de générer un nombre réel aléatoire dans la plage [0, 1) et d'effectuer une recherche binaire sur le tableau pour obtenir le plus grand indice dont le cumulatif la valeur n'est pas supérieure à la valeur choisie. J'aime plutôt cette solution, mais il semble étrange que le runtime ne prenne pas en compte les probabilités. En particulier, dans les cas extrêmes d'un côté toujours à venir ou les valeurs étant uniformément réparties, il est possible de générer le résultat du roulement en O(1) en utilisant une approche naïve, bien que mon La solution prendra toujours plusieurs étapes logarithmiques.

Quelqu'un a-t-il des suggestions sur la façon de résoudre ce problème d'une manière quelque peu "adaptative" dans son exécution?

[~ # ~] modifier [~ # ~] : Sur la base des réponses à cette question, j'ai écrit n article décrivant de nombreuses approches de ce problème, ainsi que leurs analyses. Il semble que l'implémentation de la méthode d'alias par Vose donne time (n) temps de prétraitement et O(1) temps par jet de dé, ce qui est vraiment impressionnant. dans les réponses!

122
templatetypedef

Vous recherchez la méthode alias qui fournit une méthode O (1) pour générer une distribution de probabilité discrète fixe (en supposant que vous peut accéder aux entrées dans un tableau de longueur n en temps constant) avec une configuration unique O(n). Vous pouvez le trouver documenté dans chapitre 3 (PDF) of "Génération aléatoire non uniforme de variables" par Luc Devroye.

L'idée est de prendre votre tableau de probabilités pk et produire trois nouveaux tableaux à n éléments, qk, unek, et Bk. Chaque qk est une probabilité entre 0 et 1, et chacun ak et Bk est un entier compris entre 1 et n.

Nous générons des nombres aléatoires entre 1 et n en générant deux nombres aléatoires, r et s, entre 0 et 1. Soit i = étage (r * N) +1. Si qje <s puis retourner unje sinon retour bje. Le travail de la méthode des alias consiste à déterminer comment produire qk, unek et Bk.

111
mhum

Utilisez un arbre de recherche binaire équilibré (ou une recherche binaire dans un tableau) et obtenez la complexité O (log n). Avoir un nœud pour chaque résultat de dé et les clés doivent être l'intervalle qui déclenchera ce résultat.

function get_result(node, seed):
    if seed < node.interval.start:
        return get_result(node.left_child, seed)
    else if seed < node.interval.end:
        // start <= seed < end
        return node.result
    else:
        return get_result(node.right_child, seed)

La bonne chose à propos de cette solution est qu'elle est très simple à mettre en œuvre mais a toujours une bonne complexité.

4
hugomg

Je pense à granuler votre table.

Au lieu d'avoir une table avec le cumul pour chaque valeur de dé, vous pouvez créer un tableau entier de longueur xN, où x est idéalement un nombre élevé pour augmenter la précision de la probabilité.

Remplissez ce tableau en utilisant l'index (normalisé par xN) comme valeur cumulative et, dans chaque "emplacement" du tableau, stockez le lancer de dés éventuel si cet index apparaît.

Je pourrais peut-être expliquer plus facilement avec un exemple:

En utilisant trois dés: P(1) = 0,2, P(2) = 0,5, P(3) = 0,3

Créez un tableau, dans ce cas, je choisirai une longueur simple, disons 10. (c'est-à-dire, x = 3.33333)

arr[0] = 1,
arr[1] = 1,
arr[2] = 2,
arr[3] = 2,
arr[4] = 2,
arr[5] = 2,
arr[6] = 2,
arr[7] = 3,
arr[8] = 3,
arr[9] = 3

Ensuite, pour obtenir la probabilité, il suffit de randomiser un nombre entre 0 et 10 et d'accéder simplement à cet index.

Cette méthode peut perdre sa précision, mais augmenter x et la précision seront suffisantes.

3
andrewjs