我正在解决这个问题,我们需要从X = 0到X = N.我们一次只能采取2或3步。
对于2的每一步,我们的概率为0.2,对于每步3,我们的概率为0.8。我们如何找到达到N的总概率。
e.g。达到5,
2+3 with probability =0.2 * 0.8=0.16 3+2 with probability =0.8 * 0.2=0.16 total = 0.32.
我最初的想法:
通过简单的Fibonacci序列可以找到多种方法。 F(N)= F(N-3)+ F(N-2); 但是我们如何记住数字,以便我们可以将它们相乘以找出概率?
答案 0 :(得分:6)
这可以使用Dynamic programming
来解决。
让我们在F(N)
0
=达到the starting number is N
的概率
F(N) = 0.2*F(N-2) + 0.3*F(N-3)
基本情况:
F(0) = 1 and F(k)= 0 where k< 0
所以DP代码就像那样:
F[0] = 1;
for(int i = 1;i<=N;i++){
if(i>=3)
F[i] = 0.2*F[i-2] + 0.8*F[i-3];
else if(i>=2)
F[i] = 0.2*F[i-2];
else
F[i] = 0;
}
return F[N];
此算法将在O(N)
答案 1 :(得分:2)
关于这个解决方案的一些澄清:我假设从2s和3s生成数字的唯一允许操作是加法(你的定义也允许减法)并且输入数总是有效的(2 <=输入)。定义:唯一的数字行意味着:在另一个顺序中没有其他具有相同数量的3和2的行在范围内。
我们可以将问题简化为多个小问题:
问题A:查找可以总计给定数字的所有数字序列。 (仅限唯一的数字行)
首先找到构建给定数字所需的最小3个数,这只是input % 2
。可以用这种方式计算可用于构建输入的最大3个数:
int max_3 = (int) (input / 3);
if(input - max_3 == 1)
--max_3;
现在,总计input
的所有数字序列必须保持在input % 2
和max_3
3之间。可以从给定数量的3s轻松计算出2s。
问题B:计算给定列表的概率及其排列结果
对于每个唯一的数字行,我们可以轻松地推导出所有排列。由于它们由相同的数字组成,因此它们具有相同的出现可能性并产生相同的总和。可以从行0.8 ^ number_of_3s * 0.2 ^ number_of_2s
轻松计算出可能性。下一步是计算不同的permuatation的数量。计算具有特定数量的2和3的所有不同集合可以这样做:计算集合中所有可能的2s分布:(number_of_2s + number_of_3s)! / (number_of_3s! * numer_of_2s!)
。基本上只是可能的不同排列的数量。
现在从理论到实践
由于数学已经给出,其余部分非常简单:
define prob:
input: int num
output: double
double result = 0.0
int min_3s = (num % 2)
int max_3s = (int) (num / 3)
if(num - max_3 == 1)
--max_3
for int c3s in [min_3s , max_3s]
int c2s = (num - (c3s * 3)) / 2
double p = 0.8 ^ c3s * 0.2 * c2s
p *= (c3s + c2s)! / (c3s! * c2s!)
result += p
return result
答案 2 :(得分:2)
不是跳入编程,而是使用数学。
设p(n)是到达n步之外的位置的概率。
基本情况:
p(0)=1
p(1)=0
p(2)=0.2
p(n+3)=0.2 p(n+1) + 0.8 p(n)
您可以通过查找线性递归关系的指数解来以封闭形式解决此问题。
c ^ 3 = 0.2 c + 0.8
c = 1,( - 5 + - sqrt(55)i)/ 10
虽然这是立方体,但c = 1将始终是此类问题的解决方案,因为存在恒定的非零解。
因为根是不同的,所有解都是a1(1)^ n + a2(( - 5 + sqrt(55)i)/ 10)^ n + a3(( - 5-sqrt(55)) ⅰ)/ 10)^ N。您可以使用初始条件求解a1,a2和a3:
a1=5/14
a2=(99-sqrt(55)i)/308
a3=(99+sqrt(55)i)/308
这为p(n)提供了一个非递归公式:
p(n)=5/14+(99-sqrt(55)i)/308((-5+sqrt(55)i)/10)^n+(99+sqrt(55)i)/308((-5-sqrt(55)i)/10)^n
非递归公式的一个不错的属性是你可以读取5/14的渐近值,但这也很清楚,因为跳跃的平均值是2(1/5)+ 3(4/5) )= 14/5,你几乎肯定会击中一组密度为1 /(14/5)的整数。你可以使用其他根的大小,2 / sqrt(5)~0.894,看看概率接近渐近的速度有多快。
5/14 - (|a2|+|a3|) 0.894^n < p(n) < 5/14 + (|a2|+|a3|) 0.894^n
|5/14 - p(n)| < (|a2|+|a3|) 0.894^n
答案 3 :(得分:1)
f(n,p)= f(n-3,p * .8)+ f(n -2,p * .2)
从1开始。
如果n = 0则返回p,如果n <0则返回0.
答案 4 :(得分:1)
不是使用(非常低效)递归算法,而是从头开始计算您可以通过多少种方式达到后续步骤,即使用'dynamic programming'。通过这种方式,您可以轻松地计算概率,并且还具有仅 O(n)的复杂度,以计算直到步骤 n 的所有内容。
对于每个步骤,记住达到该步骤的可能方式,如果有的话(无论如何),以及达到该步骤的可能性。对于第0步(开始),这是(1, 1.0)
。
steps = [(1, 1.0)]
现在,对于每个连续步骤n
,获取先前计算的可能方式poss
和概率prob
以达到步骤 n-2 和 n-3 (或(0, 0.0)
或n < 2
分别为n < 3
),将这些添加到组合的可能性和概率以达到新步骤,并将它们添加到列表。
for n in range(1, 10):
poss2, prob2 = steps[n-2] if n >= 2 else (0, 0.0)
poss3, prob3 = steps[n-3] if n >= 3 else (0, 0.0)
steps.append( (poss2 + poss3, prob2 * 0.2 + prob3 * 0.8) )
现在您可以从该列表中获取数字:
>>> for n, (poss, prob) in enumerate(steps):
... print "%s\t%s\t%s" % (n, poss, prob)
0 1 1.0
1 0 0.0
2 1 0.2
3 1 0.8
4 1 0.04
5 2 0.32 <-- 2 ways to get to 5 with combined prob. of 0.32
6 2 0.648
7 3 0.096
8 4 0.3856
9 5 0.5376
(代码在Python中)
请注意,这将使两者达到某个步骤的可能方式的数量(例如,“前2,然后3”或“前3,然后2”为5),和一次性达到该步骤的概率。当然,如果你只需要 概率,你可以使用单个数字而不是元组。