概率分析和随机算法
5.1雇佣问题
假设你要雇佣一个新的办公室助理,雇佣代理每天想你推荐一个应聘者(连续推荐n个),你面试这个人,如果这个应聘者比目前的办公室助理更优秀,你就会辞掉当前的办公室助理,然后聘用这个新的。面试一个人需付给雇佣代理一笔费用,聘用办公助理也需要费用。
伪代码:
HIRE-ASSISTANT(n)
best = 0
for i = 1 to n
interview candidate i
if canditate i is better than candidate best
best = i
hire candidate i
假设面试的费用为 Ci C i ,雇佣的费用为 Ch C h 。假设雇佣了m次,则算法的总费用就是 O(Cin+Chm) O ( C i n + C h m ) 。
最坏情形
当应聘者的质量按出现的次序严格递增时,这种情况就会出现,此时雇佣了n次,总的费用是 O(Chn) O ( C h n )
当然,应聘者并非总以质量递增的次序出现。事实上,我们既不知道他们出现的次序,也不能控制这个次序。因此,很自然的会问在一种典型或者平均的情形下,会有什么结果?
概率分析
概率分析就是在问题的分析中使用概率技术。为了使用概率分析,必须使用关于输入分布的知识或者对其做假设,然后分析算法,计算出一个期望的运行时间。这个期望值通过对所有可能的输入分布算出。
有些问题,我们对所有可能的输入集合做某种假设。对于其他问题,可能无法描述一个合理的输入分布,此时就不能使用概率分析方法。
在雇佣问题中,可以假设应聘者是以随机顺序出现的。假设可以对任何两个应聘者进行比较并确定哪个更优;换言之,在所有的应聘者之间存在这一个全序关系。因此可以使用从1到n的唯一号码来标志应聘者的优秀程度。用rank(i)来表示应聘者i的名次。这个有序序列 <rank(1),rank(2),...,rank(n)> < r a n k ( 1 ) , r a n k ( 2 ) , . . . , r a n k ( n ) > <script type="math/tex" id="MathJax-Element-5"> </script>是序列 <1,2,...,n> < 1 , 2 , . . . , n > <script type="math/tex" id="MathJax-Element-6"><1,2,...,n></script>的一个排列。说应聘者以随机的顺序出现,就等于说这个排名列表是1到n的n!中排列中的任何一个,每种都以相等的概率出现。
随机算法
为了利用概率分析,我们需要了解输入分布的一些信息。然而在许多情况下,我们对输入分布是不知道的。即使知道输入分布,在计算机中对其进行建模也可能是无法完成的。因此,我们可以通过使一个算法中某一部分的行为随机化,就可以利用概率和随机性作为算法设计和分析的工具。
比如在雇佣问题中,我们可以通过随机的选择一个应聘者进行面试,这样就能保证应聘序列的随机性。
如果一个算法的行为不仅由输入决定,而且也由随机数生成器产生的数值决定,则成这个算法是随机的。
大多数编程环境都会提供一个伪随机生成器,例如假设一个随机生成器RANDOM,调用DANDOM(a,b),将会返回一个介于a和b之间的整数,并且每个数以等概率出现。
5.2指示器随机变量
给定一个样本空间S和一个时间A,那么时间A对应的指示器随机变量
I{A}
I
{
A
}
定义为:
给定一个样本空间S和S中的一个事件A,设
XA=I{A}
X
A
=
I
{
A
}
,那么
其中 A− A − 表示A的补集。
用指示器随机变量分析雇佣问题
(一)一种比较麻烦的计算:
假设X是一个随机变量,表示我们雇佣的次数,
Pr{X=x}
P
r
{
X
=
x
}
表示X的概率,则X的期望值为
这个公式求解起来很麻烦,需要求解每个X=i时的概率。
(二)通过指示器随机变量
我们可以通过指示器随机变量分析上述问题,我们定义n个变量,这个n个变量与每个应聘者是否被聘用对应。特别的,假设
Xi
X
i
对应第
i
i
个应聘者被雇佣该事件的指示器随机变量。因而,
则, E[Xi]=Pr[应聘者i被雇佣] E [ X i ] = P r [ 应 聘 者 i 被 雇 佣 ]
应聘者i被雇佣的条件是:正好第i个应聘者是前i个应聘者中最优秀的一个,而由于应聘者是按随机的次序出现的,所以第i个应聘者是最优秀的应聘者的概率为
由上可得:
所以,雇佣次数X的期望 E[X]=lnn E [ X ] = l n n 。
5.3随机算法
随机排列数组
很多随机算法通过对给定的输入变换排列以使输入随机化。
(一)
一个通常的方法是为数组的每个元素A[i]赋一个随机的优先级P[i],然后依据优先级对数组A中的元素进行排序。如一个初始数组
A=<1,2,3,4>
A
=<
1
,
2
,
3
,
4
>
,随机选择优先级
P<36,3,62,19>
P
<
36
,
3
,
62
,
19
>
,则将产生一个数组
B=<2,4,1,3>
B
=<
2
,
4
,
1
,
3
>
。伪代码如下:
PERMUTE-BY-SORTING(A)
n = A.length
let P[1...n] be a new array
for i = 1 to n
P[i]=RANDOM(1,n^3)
sort A, using P as sort keys
由于需要进行排序,所以该算法时间复杂度为 θ(nlgn) θ ( n l g n ) ,取 P[i]=RANDOM(1,n3) P [ i ] = R A N D O M ( 1 , n 3 ) 是为了使得P中所有的优先级尽可能的唯一。
(二)
产生随机排列的一个更好方法是原址排列给定数组。实现过程是针对A[i],在元素A[i]到A[n]中随机选取一个元素,交换二者,迭代n次能够得到随机排列数组。伪代码
RANDOMIZE-IN-PLACE(A)
n = A.length
for i = 1 to n
swap A[i] with A[RANDOM(i,n)]
时间复杂度为 θ(n) θ ( n ) 。可以用循环不变式来证明这一过程是能产生一个均匀随机排列的。
5.4概率分析和指示器变量的进一步使用
生日悖论
一个屋子里人数必须要达到多少人,才能使其中两个人生日相同的机会达到50%?
概率分析:
我们一般采用上述事件A的补集进行求解,两个人生日相同的事件补集为——所有人的生日都不相同。假设有
k
k
个人,一年有天,则所有人的生日都不想相同的概率为
由不等式 1+x≤ex 1 + x ≤ e x ,得
所以,为了使得 Pr(A)≥1/2 P r ( A ) ≥ 1 / 2 ,则 Pr(B)≤1/2 P r ( B ) ≤ 1 / 2 ,得
当n = 365时,有 k≥23 k ≥ 23 。
指示器随机变量:
我们可以利用指示器随机变量给出生日悖论的一个简单而近似的分析。对屋子里
k
k
个人中的每一对,定义指示器变量
Xij
X
i
j
如下:
两个人生日相同的概率为1/n,因此
设X表示计数生日相同两人对数目的随机变量,我们有
则,我们得到
当 k(k−1)≥2n k ( k − 1 ) ≥ 2 n 时,生日相同的两人对的期望树至少是1,当n=365时,解得 k=28 k = 28 。因此,如果至少有28个人,我们可以期望找到至少一对人生日相同。
第一种分析仅用了概率,确定了为使存在至少一对人生日相同概率大于1/2所需的人数;第二种分析使用了指示器随机变量,给出了相同生日期望树为1时的人数。依据期望来反推概率只是简单而近似的分析,并不如分析1准确。虽然两种情形下人的准确数目不同 ,但它们在渐进阶数上是相同的,都是 θ(n−−√) θ ( n )
球与箱子
把相同的球随机投到b个箱子里,问:平均需要投多少次球,才能使箱子里至少有一个球?
一次投球落在空箱子里称为一次“命中”,我们想知道为了获得b次命中,所需要的投球次数。
分析:将投球分为b个阶段,第i个阶段代表从第i-1次命中到第i次命中的投球。如第一个阶段由于都是空箱子,所有投球次数的期望是1;第二个阶段,由于有一个箱子里有球,b-1个箱子里没有球,所以投球次数的期望是
b/(b−1)
b
/
(
b
−
1
)
;同理,第i个阶段的投球期望是
b/(b−i+1)
b
/
(
b
−
i
+
1
)
。因此全部累加b个阶段的期望投球数即可得到所期望的投球。
这个问题也称为礼券收集者问题,意思是一个人如果想要收集齐b种不同礼券中的每一种,大约需要 blnb b l n b 张随机得到的礼券。
特征序列
抛投一枚标准的硬币n次,最大连续正面的序列的期望长度有多长?答案是 θ(lgn) θ ( l g n ) 。