【问题标题】:Simulating weighted random number - Java模拟加权随机数 - Java
【发布时间】:2015-04-23 23:40:53
【问题描述】:

我查看了多篇堆栈溢出文章,但找不到合理的回应。如有重复请注明。

我有一个物品清单。比如:

String giantRat []={"Bandage", "Healing Potion", "Minor Healing Potion", "Rat Teeth", "Fur", "Rat Tail", ""};

这表示giantRat 可能掉落的物品。

有一个具有匹配索引的相关数组,它包含我希望是发生的加权概率。比如:

int giantRatDropRate[]={1,1,1,6,8,3,5};

这些将被放大为 50(每个乘以 2),然后理论上我会扮演一个 50 面的骰子 (Random)。这似乎是错误的方法,我想不出办法做到这一点。

同样,我们的想法是掷骰子并根据权重从列表中选择一项。也许掷骰子是错误的方式。任何帮助表示赞赏。

【问题讨论】:

标签: java random probability


【解决方案1】:

一个简单的方法可能如下。不需要*2,因为概率是一样的。

    String giantRat []={"Bandage", "Healing Potion", "Minor Healing Potion", "Rat Teeth", "Fur", "Rat Tail", ""};


    int[] a = {1,1,1,6,8,3,5};
    int sum = 0;
    for(int i: a)
       sum += i;
    Random r = new Random();
    int s = r.nextInt(sum);  //Get selection position (not array index)

    //Find position in the array:
    int prev_value = 0;
    int current_max_value = 0;
    int found_index = -1;
    for(int i=0; i< a.length; i++){ //walk through the array
      current_max_value = prev_value + a[i];
      //is between beginning and end of this array index?
      boolean found = (s >= prev_value && s < current_max_value)? true : false;
      if( found ){
        found_index = i;
        break;
      }
      prev_value = current_max_value;
    }

    String selection = "unknown";
    if( found_index != -1 ){
      selection = giantRat[found_index];
    }
    System.out.println(selection);

http://ideone.com/xyQlvN 的示例

【讨论】:

  • 这确实做得很好。感谢您花时间写出来。谢谢你的例子。我一定要研究清楚并更好地理解它。
  • 老兄,不要在这里打死牛,但这太棒了。我已经读了几次,虽然语法是有道理的,但逻辑超出了我的理解。不知道您是如何制定此解决方案的,但做得很好,先生。它已实施到我的游戏中并且运行良好。干得好,先生。再次感谢您抽出时间提供帮助。
  • @JosephErickson,很高兴,我很高兴它对你有用。不是严厉,但我确实同意其他答案,因为您确实应该经历从发现问题到解决问题的过程。值得花时间了解(此)代码的工作原理。随意询问行号/哪些部分不清楚。
  • 不用担心。我实际上打算开发一种不同的方法。因为我正在处理小数字(
  • @pds 在你建议我不要浮在你的桂冠上之后,请参阅下面的我自己的答案。感谢您的帮助。 (是的,我在下面喊了你一声)。
【解决方案2】:

使用 Random.nextInt(n),其中 n 是权重的总和;然后,根据结果 int 下降的间隔,您确定项目;例如如果为 0 - 取第一项;如果它在 3 到 8 之间(含)- 取第四项。

您可以轻松地将权重数组转换为区间边界数组:只需将所有前面的元素相加即可。 然后,使用随机 int,只需越过这个区间边界数组,并在您的随机 int 变得大于数组的当前元素时停止。

因为区间的长度是由权重决定的,所以概率也是由它决定的。

【讨论】:

  • 确定间隔的方法是什么?
  • 我试图解释如何确定间隔并在原始答案中使用它们。
【解决方案3】:

只需计算每个元素具有的值的区间。让我们忘记乘以 2 不会带来任何东西。

第一个元素的权重为 1,因此它的区间为[0, 1[

第二个的权重为 1,所以让我们从前一个的值开始它的间隔,并添加 1:[1, 2[

第三个也一样:[2, 3[

第4个的权重是6,所以它的区间是[3, 9[

继续直到结束。

然后掷骰子,找到区间覆盖骰子值的元素。

【讨论】:

  • 是否有股票 java 类来检查间隔?我觉得我经常遇到这个问题,因为 switch 语句不灵活。
  • 不在 JDK 中。但这只是 10 行代码的问题。
  • 请澄清10行?抱歉,如果您的回答是含蓄的,我对编程很陌生,所以必须为我说明一切。另外,感谢您的回复。
  • 我不会为你写代码。尝试一些东西。什么是间隔?这是一个下限(int)和一个上限(int)。你怎么知道一个区间是否包含一个数字?如果下限是 数字。把它写成代码,你就有了你的课。
  • 没有人要求编写代码。此外,我发现当我对某个主题有专业知识并且有人真诚地寻求指导时,如果我对自己的专业知识不那么居高临下,那么互动似乎会更好。这些建议可能会对您的生活有所帮助。
【解决方案4】:

您可以这样做的一种方法是将每个索引存储在大小为 50 的数组中。所以:

 int[] giantRatDropRate = new int[50];
 giantRatDropRat = { 0 , 0 , 1 , 1 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3... };

然后如果你喜欢,你可以随机打乱数组,参考Random shuffling of an array

最后,使用随机数生成器从该数组中获取索引: 双 d = 50.0 * Math.random(); 字符串动作 = GiantRat[giantRatDrop[(int)d]];

【讨论】:

    【解决方案5】:

    好消息:我采用了 @pds 在 cmets 部分中建议的非严苛方法,并提出了自己的解决方案。我认为答案部分中的@pds 解决方案是一个更有说服力的解决方案,但这是我在研究他并稍微思考一下我的问题后的个人看法:

    https://gist.github.com/anonymous/f985c1839e5a6be94883

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 2018-03-15
      • 1970-01-01
      • 1970-01-01
      • 2019-11-11
      • 2023-03-31
      • 1970-01-01
      相关资源
      最近更新 更多