【问题标题】:How to pick a number based on probability?如何根据概率选择一个数字?
【发布时间】:2015-08-22 07:11:53
【问题描述】:

我想从0,1,2,3...n 中选择一个随机数,但是我想通过将x 与选择k - 1 相乘来降低选择k|0<k<n 的机会x = (k - 1) / k。数字越大,捡到的机会越小。

作为答案,我想看看下一个方法的实现:

int pickANumber(n,x)

这是针对我正在开发的游戏,我认为这些问题相关但不完全相同:

【问题讨论】:

  • 我认为你的意思是“k | 0
  • @j_random_hacker 是的,tnx
  • 哇,这个真的不清楚。

标签: algorithm math probability


【解决方案1】:
p1 + p2 + ... + pn = 1
p1 = p2 * x
p2 = p3 * x
...
p_n-1 = pn * x

解决这个问题给你:

p1 + p2 + ... + pn = 1
(p2 * x) + (p3 * x) + ... + (pn * x) + pn = 1
((p3*x) * x) + ((p4*x) * x) + ... + ((p_n-1*x) * x) + pn = 1
....
pn* (x^(n-1) + x^(n-2) + ... +x^1 + x^0) = 1
pn*(1-x^n)/(1-x) = 1
pn = (1-x)/(1-x^n)

这为您提供了需要设置为pn 的概率,并且您可以从中计算所有其他 p1,p2,...p_n-1 的概率

现在,您可以使用“黑盒”RNG 来选择具有分布的数字,就像您提到的线程中的那些。

一个简单的方法是设置一个辅助数组:

aux[i] = p1 + p2 + ... + pi

现在,在0aux[n]之间绘制一个均匀分布的随机数,并使用二分查找(辅助数组排序),得到第一个值,aux中的匹配值大于随机均匀你得到的号码


原始答案,用于减法(在编辑问题之前):

对于n项目,你需要解方程:

p1 + p2 + ... + pn = 1
p1 = p2 + x
p2 = p3 + x
...
p_n-1 = pn + x

解决这个问题给你:

p1 + p2 + ... + pn = 1
(p2 + x) + (p3 + x) + ... + (pn + x) + pn = 1
((p3+x) + x) + ((p4+x) + x) + ... + ((p_n-1+x) + x) + pn = 1
....
pn* ((n-1)x + (n-2)x + ... +x + 0) = 1
pn* x = n(n-1)/2
pn = n(n-1)/(2x)

这为您提供了需要设置为pn 的概率,并且您可以从中计算所有其他 p1,p2,...p_n-1 的概率

现在,您可以使用“黑盒”RNG 来选择具有分布的数字,就像您提到的线程中的那些。


请注意,这不能保证您将有一个解决方案,例如 0<p_i<1 用于所有 i,但您不能保证满足您的要求,这将取决于 n 和 @ 的值987654336@ 适合。

【讨论】:

  • 不是 p1 = p2 + x 而是 p1 = p2 * x,这是我在问题描述中的错误。我用乘法计算律。对不起
  • @Ilya_Gazman 您的问题是“按 x 降低”,这意味着减法,而不是除法。无论如何,除法可以非常相似地完成 - 但使用几何级数而不是算术级数进行求和,并得到公式
  • @Ilya_Gazman 我添加了一个乘法解决方案,原理相同。您还可以查看指数分布,这是一个接近的变体,虽然是一个连续的变体。
  • @Ilya_Gazman 至于加法解决方案(减法,而不是除法),请注意我明确写的内容 - 它不适用于某些值,因为它可能导致某些 pi 的负值,或者值大于 1。如果不放宽要求,您将无能为力,因为这是使用 n 变量解决 n 线性公式的答案,并且有一个单一的解决方案
【解决方案2】:

编辑这个答案是针对 OPs 原始问题的,不同之处在于每个概率都应该比前一个概率低一个固定的数量。

好吧,让我们看看约束是怎么说的。你想要 P(k) = P(k - 1) - x。所以我们有:

P(0)

P(1) = P(0) - x

P(2) = P(0) - 2x ...

此外,总和k P(k) = 1。总结,我们得到:

1 = (n + 1)P(0) -x * n / 2 (n + 1),

这为您提供了 xP(0) 之间的简单约束。根据另一个解决一个问题。

【讨论】:

    【解决方案3】:

    为此,我将使用 Mersenne Twister 算法进行 Boost 提供的均匀分布,然后使用映射函数将该随机分布的结果映射到实际数字选择。

    这里是一个潜在实现的简单示例,虽然我省略了二次方程实现,因为它众所周知:

    int f_of_xib(int x, int i, int b)
    {
        return x * i * i / 2 + b * i;
    }
    
    int b_of_x(int i, int x)
    {
        return (r - ( r ) / 2 );
    }
    
    
    int pickANumber(mt19937 gen, int n, int x)
    {
        // First, determine the range r required where the probability equals i * x
        // since probability of each increasing integer is x higher of occuring.
        // Let f(i) = r and given f'(i) = x * i then r = ( x * i ^2 ) / 2 + b * i
        // where b = ( r - ( x * i ^ 2 ) / 2 ) / i . Since r = x when i = 1 from problem
        // definition, this reduces down to b = r - r / 2. therefore to find r_max simply
        // plugin x to find b, then plugin n for i, x, and b to get r_max since r_max occurs
        // when n == i.
    
        // Find b when 
        int b = b_of_x(x);
        int r_max = f_of_xib(x, n, b);
    
        boost::uniform_int<> range(0, r_max);
        boost::variate_generator<boost::mt19937&, boost::uniform_int<> > next(gen, range);
    
        // Now to map random number to desired number, just find the positive value for i
        // when r is the return random number which boils down to finding the non-zero root
        // when 0 = ( x * i ^ 2 ) / 2 + b * i - r
        int random_number = next();
    
        return quadtratic_equation_for_positive_value(1, b, r);
    }
    
    
    
    int main(int argc, char** argv)
    {
        mt19937 gen;
        gen.seed(time(0));
    
        pickANumber(gen, 10, 1);
    
        system("pause");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-21
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 2016-01-30
      • 2013-03-22
      • 2013-08-27
      • 1970-01-01
      相关资源
      最近更新 更多