【问题标题】:Recursive loops递归循环
【发布时间】:2018-06-27 04:16:18
【问题描述】:

问题是返回概率,如果您从 10,000 开始并且需要达到 20,000,并且您每次下注 1,000(达到 20,000 的概率在您达到 0 之前)。您有 50-50 的输赢变化。

public static double roulette( double start, double end, double bet) {

    if (start >= end) return 1;
    if (start <= 0) return 0;

        return .5*roulette(start+2*bet,end,bet) + .5*roulette(start-bet,end,bet);
}

但它会陷入无限循环,因为一些递归调用将重新开始。就像我打了一个 start = 11,000 的电话,它会回到 10,000 并创建一个循环。我该如何防止这种情况?

【问题讨论】:

  • 您的程序是否为较小的输入返回正确的概率?对于限制说 1000 - 2000 ?
  • 解决方案必须是递归的吗?
  • 我建议尝试使用调试器单步执行您的代码,或者添加打印语句,以便您了解实际发生的情况。这里的任何人都很难仅根据问题来调试您的代码。
  • 是的,这适用于任何不返回原始函数的递归调用。假设 start = 100, end = 200, bet = 50。那么它将调用 200 并返回 1,然后在 150 上,它可以完成 +100 调用并返回 1,但随后它将达到 150-50 = 100从一开始就卡住了。
  • OP 解释了代码的确切问题 - roulette(10000, 20000, 1000) 调用 roulette(11000, 20000, 1000) 调用 roulette(10000, 20000, 1000)。因此无限循环。

标签: java recursion infinite-loop probability


【解决方案1】:

对于关于“在到达 0 之前达到 20,000 的概率”的具体查询,可以通过 Random Walk over a one dimensional graph 来解决,如下所述:

“如果 a 和 b 是正整数,那么从 0 开始的一维简单随机游走首先到达 b 或 -a 的预期步数为 ab。此游走在 -a 之前到达 b 的概率为b/(a+b),可以从简单随机游走是鞅这一事实推导出来。”

给定,步行原点 = 10000,a=10000(距 0 的距离),b=10000(距 20000 的距离),& 步长 =1000: 在 -a = 10000/(10000 + 10000) = 1/2 之前到达 b 的概率。

不确定这是否就是您想要实现的全部,这将是一行返回语句。

另一方面,给定的实现最终将探索可能解决方案的整个空间(即达到 0 或 20000 的所有可能方式)。请参阅RandomWalk.pdf 中的概率和帕斯卡三角形部分,了解其增长模式及其长期运行时间。您的实现已经开始沿着帕斯卡三角形的最右边的分支/对角线进行探索,并继续探索所有可能的分支。

相反,一种替代方法可能是尝试实现一种方法,该方法计算第一次达到 20000(或 0)的概率(不是以所有可能的方式)然后中断。选择右(赢)或左(输)at random。对几次运行的数字进行平均,这应该非常接近概率,如上面计算的 ~1/2。

有趣的是,n 步后随机游走所覆盖的预期距离 = sqrt(n)。这可用于估计正确实现的算法达到 20000 或 0 所需的迭代次数或递归调用次数(复杂度)。 在这种情况下,距离 n = ((20000-10000)/1000) = 10,平均需要大约 n*n = 100 步/迭代。

【讨论】:

    【解决方案2】:

    这是一个建议的迭代解决方案(我将实现留给您):

    为了更短,让我们找到roulette(10,20,1)(相当于你的roulette(10000,20000,1000))。让我们用r(10) 表示roulette(10,20,1)

    现在,让我们计算r(i),其中i0 变为20

    • r(0) = 0 - 即如果您没有钱,就没有机会获胜。
    • r(20) = 1 - 因为这意味着你赢了。

    现在让我们计算另一个r(i)s:

    • r(1) = 0.5 * r(2) + 0.5 * r(0) = 0.5 * r(2) + 0 = 1/2 * r(2)

    • r(2) = 0.5 * r(3) + 0.5 * r(1) = 0.5 * r(3) + 0.5 * (0.5 * r(2))

    意思是

    • r(2) = 2/3 * r(3)

    如果你继续这些计算,你会发现

    • r(3) = 3/4 * r(4)
    • r(4) = 4/5 * r(5)

    ...

    • r(18) = 18/19 * r(19)
    • r(19) = 19/20 * r(20) = 19/20 * 1 = 19/20

    现在我们找到了r(19),我们可以找到r(18)

    • r(18) = 18/19 * 19/20 = 18/20
    • r(17) = 17/18 * r(18) = 17/18 * 18/20 = 17/20

    ...

    • r(10) = 10/20 = 0.5

    因此,如果您从 10000 开始并且需要达到 20000,并且您每次下注 1000,那么您有 50% 的机会达到 20000。

    【讨论】:

      【解决方案3】:

      正如我在 cmets 中提到的,概率是所有以 start &gt;= endleft &lt; 0 结尾的概率的总和。

      static double roulette(double start, double end, double bet, int left) {
          if (start >= end && left >= 0)
              return 1; // you definitely win.
          if (start < bet || left < 0)
              return 0; // you cannot win.
          double win = 0.5 * roulette(start + bet, end, bet, left - 1);
          double lose = 0.5 * roulette(start - bet, end, bet, left - 1);
          return win + lose; // you get a 0.5-0.5 to win or lose.
      }
      

      例如,假设 start 是 100,end 是 200,bet 是 50。 如果总数为 2,则只有一种方式:100->150->200,即概率为 0.25。但是如果总数是4,你可以有以下几种获胜方式:100->150->200、100->150->100->150->200、100->50->100->150-> 200。获胜的概率是0.375。

      【讨论】:

        猜你喜欢
        • 2017-01-21
        • 1970-01-01
        • 2013-08-12
        • 2011-02-09
        • 2023-04-02
        • 2011-08-11
        • 2015-01-26
        • 1970-01-01
        相关资源
        最近更新 更多