【问题标题】:Trying to achieve a simple algorithm试图实现一个简单的算法
【发布时间】:2012-01-26 13:04:07
【问题描述】:

我有 N 个选项,从 1 到数千。例如,我会用 3 个选项来解释它,但我需要这个算法适用于 N 个选项。

  • A=30% 的可能性
  • B=50% 的可能性
  • C=20% 的可能性

我需要随机获得这三个选项之一,但要根据概率。

我通过生成一个介于 0 和 100 之间的随机数来实现它,并且我正在做一些繁重而丑陋的代码来了解数字何时介于 0 和 A 可能性数之间、A 可能性和 B 可能性之间等.

你知道更好的方法吗?

【问题讨论】:

  • 请发布您的代码的相关部分,以便我们看到您已经做了什么。
  • 建议:远离多语言源文件。当语言是 C 和 C++ 时,情况很糟糕,当它们是 C 和 Java 时,情况要糟糕得多:)

标签: java c algorithm


【解决方案1】:

在您需要的范围内选择一个随机数,开始从该数字中减去每个选项的概率,直到达到 0。最后减去的概率就是您想要的。

int[] possibilities = new int[] {20,50,30};
Random rand = new Random();
int r = rand.nextInt(100);
int i = 0;
for (i=0;i<possibilities.length; i++) {
  r -= possibilities[i];
  if (r <= 0)
    break;
}
System.out.println(i); // the index of the possibility

【讨论】:

  • 如果可能性是 [20,50,20,10],那么循环总是会在前 20 次中断,而不会在后 20 次中断。
  • @JoeAxon 为什么?其中循环中断取决于随机的 r。如果 r 为 80,那么它将在 2 日 20 日中断。
  • 对于大量 N 来说是“慢”
  • @PierreHabouzit 它不是“慢”,而是 O(N)。因为你必须阅读你的输入,所以你不能做得比 O(N) 更好。
  • @yurib 你能详细说明一下吗?我不相信你的说法是正确的。
【解决方案2】:

即使给定大量不同的选项(假设您不止一次地从同一组选项中选择),执行此操作的一种方法也是高效的,即构建一个累积概率表,然后对它们进行二分搜索。

也就是说,假设您有以下期望的结果:[0.2, 0.2, 0.5, 0.05, 0.05]

我们通过使每个元素成为原始列表中所有先前元素的总和来构建一组累积概率:[0.0, 0.2, 0.4, 0.9, 0.95]

为了随机选择一个结果,我们生成一个介于 0 和 1 之间的随机数,并对列表进行二分搜索以找到比它小的最大索引。这将根据它与前一个元素之间的差距(即原始概率的数量)按比例选择每个元素。

【讨论】:

    【解决方案3】:

    如何生成一个可能性“地图”,例如:a - 30、b - 80 (a + 50%)、c - 100 (b + 20%)

    m = [30, 80, 100]

    然后您生成一个从 0 到 100 的数字,并开始检查从 a 到 c 并在第一个为真时停止。

    int[] m = {30, 80, 100};
    Random rand = new Random();    
    int r = rand.nextInt(100);
    for (int i = 0; i < m.length; i++){ 
        if (r < m[i]){
             // the i-th possibilty occured!
             break;
        }
    }
    

    【讨论】:

    • +1 因为你有一个排序集,所以二进制搜索可以用来快速找到所需的索引而不是线性搜索
    【解决方案4】:

    创建一个包含与您所需粒度一样多的元素的表格,例如。对于 1%,它将是 100 个元素表。 根据您所需的概率分布在表格中填写您的选项 绘制一个与元素表相同范围的随机整数。 将其用作索引以从表中获取您的选项。

    假设(为简单起见)您只允许 10% 的更改和您给定的 A、B、C 选项 然后 (伪代码)

    chances[]={A,A,A,B,B,B,B,B,C,C} 
    index=random() //make sure you get an int number in the range 0..9 here  
    myChance=chances[index]
    

    它使用更多的内存作为基于概率表的循环,但它是 O(1),这对于大 N 和如果你需要重复绘制会产生影响

    【讨论】:

      【解决方案5】:

      创建一个更大的数组,其中包含与所需频率成比例的值 1、2、3 ... 的实例。例如,创建一个包含 100,000 个条目的数组,如果 #342 为 7%,则将 342 的 7 个副本放入您的大数组中。然后使用统一随机数和模除法从大数组中随机选择一个值。

      (请注意,如果您的概率为整数 % 并加到 100,则大数组的大小将是可能性数量的 100 倍。要获得更精细的粒度,数组必须更大。)

      【讨论】:

        【解决方案6】:

        假设机会存储在 chances 数组中,您可以使用类似:

        srand(time(NULL));
        const double chances[] = {
            0.2, 0.3, 0.1, 0.4
        };  
        const double sigma = 1e-6;
        int i, max = sizeof(chances)/sizeof(double);
        double cumulative = 0.0, random_value = (double)rand()/(double)RAND_MAX;
        for ( i = 0; i < max; i++ ) {
            cumulative += chances[ i ];
            if ( random_value - cumulative < sigma ) break;
        }
        printf( "Index of chance: %d\n", i );
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多