概率分析和随机算法(2)——算法导论(6)

1. 引言

接下来几篇将通过几个有趣的例子继续探究概率分析随机算法

2. 生日悖论

(1) 问题的提出

我们的第一个例子是生日悖论:一个屋子里人数必须要达到多少人,才能使其中两人的生日相同的机会达到50%。你可能认为是365 / 2,但事实上,答案是一个很小的数值。下面我们对这个问题进行分析。

(2) 分析问题

我们首先找出问题的关键。这个问题的关键就是:人数(设为k)和他们中两人生日相同的概率(设为P1)的关系。要分析P1,我们可以从两个方面(直接正面思考和从其对立面思考)进行思考:

需要提前说明的是,

a. 我们对屋子里的k个人进行了从1~k的依次编号;

b. 我们不考虑闰年的情况,即1年是N = 365天。我们对每一天也进行了编号,编号方式是一年中的第n天编号为n;

c. 我们设bi表示编号为i的人的生日,bi = n表示编号为i的人的生日是编号为n的那天。显然有,1≤bi≤365。

d. 我们还假设生日均匀分布在一年中的n天中,因此概率P(bi = n) = 1 / N;

方式①:我们直接从正面去思考,即存在两人生日相同的概率

不失一般性,我们记bi和bj分别表示i和j两人的生日,那么两人生日落在第n天的概率P(bi = bj = n) = P(bi = n) * P(bj = n) = 1 / N²。那么两人生日落在同一天的概率:

我们用计数变量Xij来表示i和j两人的生日是否相同(如果相同Xij = 1,否则Xij = 0),由上面的结论,P(Xij) = 1 / N;我们设随机变量X表示k人中生日两两相同的对数。则:

由E(X) ≥1可解得,n≥28。这就是说,屋子里至少需要有28人,我们可以期望找到至少一对人生日相同。

方式②:我们再从对立面去考虑该问题,即任意两人生日都不同的概率

我们设Ai表示对于所有j<i,i与j生日都不同的事件;设Bk表示k个人生日都不同的事件。则有:

贝叶斯定理

由此我们可以递归的得到:

显然,P(B1)=1,而P(Ak|Bk-1)=(n-k+1)/n(因为P(Ak|Bk-1)的意思是在k-1人生日都不同的情况下,第k个人生日与前面k-1个人不同的概率),因此有:

有不等式 ,我们得出:

由1-P(Bk)<=50%得:k≥23。这就是说如果至少有23个人在一间屋子里,那么至少有两个人生日相同的概率至少是50%。

3. 总结

第一种分析方式使用了指示器随机变量,给出了相同生日期望为1时的人数;而第二种方式仅使用了概率,确定了为使至少存在一对人生日相同的事件发生的概率大于50%,至少需要多少人。虽然两种情形下人的准确数目不同,但它们在渐进阶数上是相等的,都为θ(√n)(如果你去解上面的不等式,你就会发现)。

ps:以上内容均摘自《算法导论》中文译本。本人只是提取出文中个人认为比较重要的点,加入了一些个人理解,仅供参考。

时间: 2024-10-28 14:37:35

概率分析和随机算法(2)——算法导论(6)的相关文章

随机快排算法

1 package Sort; 2 3 import org.junit.Test; 4 5 // 随机快排算法 6 public class RandQuickSort { 7 8 // 交换数组中的两个元素 9 public void exchange(int[] array, int index1, int index2) { 10 int tmp = array[index1]; 11 array[index1] = array[index2]; 12 array[index2] = t

【Kaggle】用随机森林分类算法解决Biologial Response问题

Kaggle搞起来 Kaggle比赛多依靠机器来自动处理,机器学习几乎是必须要的技能.开始搞Kaggle需要的机器学习技能并不深入,只是需要对于机器学习的常见几个方法有基本了解即可,比如说对于一个问题,你可以认识到它是个classification的问题啊还是regression的问题啊,为什么机器可以根据你输入的一个矩阵来算出来分类结果啊. 其实有时候真的在于是不是愿意踏出那一步,一旦踏出了那一步,做与不做真的是天壤之别. hacker的方式就是通过不断的尝试来学习,所以,搞机器学习,不实践,

负载均衡算法(三)加权随机负载均衡算法

/// <summary> /// 加权随机负载均衡算法 /// </summary> public static class WeightRandom { static Dictionary<string, int> dic = new Dictionary<string, int> { { "192.168.1.12", 1}, {"192.168.1.13", 1 }, { "192.168.1.14&

随机红包生成算法-python实现

抢红包那么开心,那你知道红包随机算法是怎么样的吗? 我模拟写了一个定额随机红包生成算法,如下. 输入: 红包总额,total 份数,num 调控参数(调控红包最平均差,默认为2) 约束: 每份最少有1分钱,即0.01 份数需为正整数 红包总额 <= 份数×0.01 输出 随机红包序列,序列长度等于红包份数 运气王,即红包数额最大的一份 # -*- coding: cp936 -*- # 思路:先随机出来m个数,然后平均分成m个数字只和的份数,然后将钱平均分给m个人# import random

随机洗牌算法

随机洗牌算法: 时间和空间复杂度都为O(n). 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 54; 6 7 void random_shuffle(vector<int> &a) 8 { 9 srand(int(time(0))); 10 int aSize = a.size(); 11 for(int i = 1; i != aSize; ++i) { 12 int j

随机洗牌算法Knuth Shuffle和错排公式

Knuth随机洗牌算法:譬如现在有54张牌,如何洗牌才能保证随机性.可以这么考虑,从最末尾一张牌开始洗,对于每一张牌,编号在该牌前面的牌中任意一张选一张和当前牌进行交换,直至洗到第一张牌为止.参考代码如下: void knuth() { for (int i = 54; i > 1; i--) { int id = rand() % (i - 1) + 1; swap(a[i], a[id]); } } 由上述方法可知,每一张牌经过洗牌之后一定不会出现在原来位置,那么一共会有多少情况呢,这其实就

Dijkstra算法——《算法导论》学习心得(十三)

这两天在做一个项目,关于北京市出租车的,然后用到了Dijkstra算法,所以这篇文章就先写Dijkstra算法了.在大二下的时候学了数据结构,书里面也讲了Dijkstra算法,但是当时怎么也没理解,结果考试的时候就考了,哎蛋疼!现在用到了,又得硬着头皮去学,结果很快弄明白了,只是在写代码时出了一些很低级的错误,调Bug用了不少时间.最后总结只能说:不是你不会,而是没到你非会不可的地步!在这篇文章里我就用实际的项目给大家讲Dijkstra算法. 背景: 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉

最短路算法 :Bellman-ford算法 &amp; Dijkstra算法 &amp; floyd算法 &amp; SPFA算法 详解

 本人QQ :2319411771   邮箱 : [email protected] 若您发现本文有什么错误,请联系我,我会及时改正的,谢谢您的合作! 本文为原创文章,转载请注明出处 本文链接   :http://www.cnblogs.com/Yan-C/p/3916281.html . 很早就想写一下最短路的总结了,但是一直懒,就没有写,这几天又在看最短路,岁没什么长进,但还是加深了点理解. 于是就想写一个大点的总结,要写一个全的. 在本文中因为邻接表在比赛中不如前向星好写,而且前向星效率并

算法概念--算法汇总大全

算法 1)算法部分主要由头文件<algorithm>,<numeric>和<functional>组成. 2)<algorithm>是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较.交换.查找.遍历操作.复制.修改.反转.排序.合并等等. 3)<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作. 4)<functional>中则定义了一些模板类,用以声明函数对象.