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

1. 雇用问题

(1) 提出问题

    你的老板让你为公司雇用一名程序员,现在有n个人投了简历。你每天会随机的从这n份简历中挑选一份,然后让对应的投简历者过来面试,每次面试都将花费C1。而你的雇用原则是:如果当前面试的程序员比目前的程序员优秀,那么你就辞掉目前的程序员,而花高价C2去聘请面试的这位程序员。你的老板愿意为该策略付费,但是想让你估算一下该费用会是多少。

下面是这种策略的伪代码:

 

 

 

 

 

 

 

(2) 不科学的算法

    因为不管最优秀的面试者出现在哪一个位置,我们总是要面试完所有人,因此面试的费用是固定的,为C1*n;假设在这n次面试中,需要雇佣m个人,那么你将花费C2 * m雇佣费。因此总费用w为:  w = C1*n +  C2 * m。

   你可能认为最好的情况是:最优秀的面试者出现在第一位,m=1;最坏的情况是:最优秀的面试者出现在最后一位,m=n。因此平均情况是,m = (n+1)/ 2。这种简单的由上下限取平均的做法在这里是不科学的,因为总费用m的分布并不是均匀的(从下面可以看出)。

2. 概率分析

我们考虑平均要雇用的人数m。设随机变量Xi表示第i名面试的人是否被雇用(若被雇佣Xi为1,否则为0)。

那么因此m的期望E(m) 为:

因此平均将花费:w = C1*n + C2 * E(m) = O(ln n),这比最坏情况下的雇用费用O(n)有了很大的改进。

3. 随机算法

   

    在上面,我们通过对m的分布分析出平均情况,但是在很多时候,我们是无法得知输入分布信息的。但我们也许可以设计一个随机算法。

    针对上面的雇用问题,我们可以在算法运行前先随机地排列应聘者,以加强所有的排列都是等可能出现的。

    下面是随机算法的伪代码描述:

    

    现在我们关心的重点在于如何生成一个随机的排列。不失一般性,我们假定一个数组A,包含1~n 这n个元素,我们的目标是构造出数组A的随机数组。下面介绍两种算法:

    方法① :我们先构造一个长度为n的数组P,数组P中的元素是介于1到n3的随机数。然后我们把数组P中的元素作为数组A中对应位置元素的优先级,数组A中的元素按照优先级大小进行排列(优先级相等的随便排列)。例如,A={1, 2, 3, 4}, P = {13,1, 60, 28}(数组P说明 数组A中,1的优先级是13,2的优先级是1,…),那么排列后的A={2,1,4,3}(按优先级从小到大排列)。伪代码如下:

至于排序算法,举不胜数,以后会专门讨论。

证明略(有兴趣的可以自己去看原书)。

    方法②:比较简单,直接贴出伪代码:

证明略。

下面给出这两种随机数组的生成算法的Java实现代码:

public static void main(String[] args) {
	printArray(permuteBySort(10));
	printArray(randomizeInPlace(10));
}

/**
 * 生成随机数组(方法1)
 *
 * @param length
 *            数组规模
 * @return
 */
private static int[] permuteBySort(int length) {
	int[] a = new int[length];
	for (int i = 0; i < length; i++) {
		a[i] = i + 1;
	}
	Random random = new Random(System.currentTimeMillis());
	int[] p = new int[length];
	for (int i = 0; i < p.length; i++) {
		// 注意这里强制类型转换很可能会丢失数据
		p[i] = random.nextInt((int) Math.pow(length, 3)) + 1;
	}
	// 冒泡排序法
	for (int i = 0; i < p.length; i++) {
		for (int j = 0; j < p.length - 1 - i; j++) {
			if (p[j] > p[j + 1]) {
				int temp = p[j];
				p[j] = p[j + 1];
				p[j + 1] = temp;
				temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
		}
	}
	return a;
}

/**
 * 生成随机数组(方法2)
 *
 * @param length
 *            数组规模
 * @return
 */
private static int[] randomizeInPlace(int length) {
	int[] a = new int[length];
	for (int i = 0; i < length; i++) {
		a[i] = i + 1;
	}
	Random random = new Random(System.currentTimeMillis());
	for (int i = 0; i < a.length; i++) {
		int swapIndex = random.nextInt(a.length - i) + i;
		int temp = a[i];
		a[i] = a[swapIndex];
		a[swapIndex] = temp;
	}
	return a;
}

/**
 * 打印数组
 *
 * @param a
 */
private static void printArray(int[] a) {
	for (int i : a) {
		System.out.print(i + "  ");
	}
	System.out.println();
}

 

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

时间: 2024-10-23 09:06:13

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

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

1. 引言 接下来几篇将通过几个有趣的例子继续探究概率分析和随机算法. 2. 生日悖论 (1) 问题的提出 我们的第一个例子是生日悖论:一个屋子里人数必须要达到多少人,才能使其中两人的生日相同的机会达到50%.你可能认为是365 / 2,但事实上,答案是一个很小的数值.下面我们对这个问题进行分析. (2) 分析问题 我们首先找出问题的关键.这个问题的关键就是:人数(设为k)和他们中两人生日相同的概率(设为P1)的关系.要分析P1,我们可以从两个方面(直接正面思考和从其对立面思考)进行思考: 需要

Randomize select algorithm 随机选择算法

从一个序列里面选择第k大的数在没有学习算法导论之前我想最通用的想法是给这个数组排序,然后按照排序结果返回第k大的数值.如果使用排序方法来做的话时间复杂度肯定至少为O(nlgn). 问题是从序列中选择第k大的数完全没有必要来排序,可以采用分治法的思想解决这个问题.Randomize select 算法的期望时间复杂度可以达到O(n),这正是这个算法的迷人之处.具体的算法分析可以在<算法导论>这本书里查看. 贴出伪代码: RANDOMIZED-SELECT(A, p, r, i) 1 if p =

算法系列笔记2(静态表顺序统计-随机选择算法)

问题:当给定存在静态表(如数组)中的n个元素,如何快速找到其中位数.最小值.最大值.第i小的数? 首先想到的方法是先对数组元素进行排序,然后找到第i小的元素.这样是可行的,但比较排序最快也需要O(nlgn),能否在线性时间内解决呢.这就是随机的分治法-随机选择. 思想:利用随机划分(在快速排序中介绍过)找到主元r,这样就将小于等于r的元素放在了其左边,大于r的元素放在了其右边.这是可以计算出r的rank为k,如果正好等于i,则就返回该元素:如果k大于i,则在左边中寻找第i小的元素,否则在右边中寻

Bagging与随机森林算法原理小结

在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合.本文就对集成学习中Bagging与随机森林算法做一个总结. 随机森林是集成学习中可以和梯度提升树GBDT分庭抗礼的算法,尤其是它可以很方便的并行训练,在如今大数据大样本的的时代很有诱惑力. 1.  bagging的原理 在集成学习原理小结中,我们给Bagging画了下面一张原理图. 从上图可以看出,

R语言︱决策树族——随机森林算法

笔者寄语:有一篇<有监督学习选择深度学习还是随机森林或支持向量机?>(作者Bio:SebastianRaschka)中提到,在日常机器学习工作或学习中,当我们遇到有监督学习相关问题时,不妨考虑下先用简单的假设空间(简单模型集合),例如线性模型逻辑回归.若效果不好,也即并没达到你的预期或评判效果基准时,再进行下换其他更复杂模型来实验. ---------------------------------------------- 一.随机森林理论介绍 1.1 优缺点 优点. (1)不必担心过度拟合

spark 随机森林算法案例实战

随机森林算法 由多个决策树构成的森林,算法分类结果由这些决策树投票得到,决策树在生成的过程当中分别在行方向和列方向上添加随机过程,行方向上构建决策树时采用放回抽样(bootstraping)得到训练数据,列方向上采用无放回随机抽样得到特征子集,并据此得到其最优切分点,这便是随机森林算法的基本原理.图 3 给出了随机森林算法分类原理,从图中可以看到,随机森林是一个组合模型,内部仍然是基于决策树,同单一的决策树分类不同的是,随机森林通过多个决策树投票结果进行分类,算法不容易出现过度拟合问题. 图 3

R语言︱机器学习模型评估方案(以随机森林算法为例)

R语言︱机器学习模型评估方案(以随机森林算法为例) 笔者寄语:本文中大多内容来自<数据挖掘之道>,本文为读书笔记.在刚刚接触机器学习的时候,觉得在监督学习之后,做一个混淆矩阵就已经足够,但是完整的机器学习解决方案并不会如此草率.需要完整的评价模型的方式. 常见的应用在监督学习算法中的是计算平均绝对误差(MAE).平均平方差(MSE).标准平均方差(NMSE)和均值等,这些指标计算简单.容易理解:而稍微复杂的情况下,更多地考虑的是一些高大上的指标,信息熵.复杂度和基尼值等等. 本篇可以用于情感挖

随机森林 算法过程及分析

简单来说,随机森林就是Bagging+决策树的组合(此处一般使用CART树).即由很多独立的决策树组成的一个森林,因为每棵树之间相互独立,故而在最终模型组合时,每棵树的权重相等,即通过投票的方式决定最终的分类结果. 随机森林算法主要过程: 1.样本集的选择. 假设原始样本集总共有N个样例,则每轮从原始样本集中通过Bootstraping(有放回抽样)的方式抽取N个样例,得到一个大小为N的训练集.在原始样本集的抽取过程中,可能有被重复抽取的样例,也可能有一次都没有被抽到的样例. 共进行k轮的抽取,

随机森林算法demo python spark

关键参数 最重要的,常常需要调试以提高算法效果的有两个参数:numTrees,maxDepth. numTrees(决策树的个数):增加决策树的个数会降低预测结果的方差,这样在测试时会有更高的accuracy.训练时间大致与numTrees呈线性增长关系. maxDepth:是指森林中每一棵决策树最大可能depth,在决策树中提到了这个参数.更深的一棵树意味模型预测更有力,但同时训练时间更长,也更倾向于过拟合.但是值得注意的是,随机森林算法和单一决策树算法对这个参数的要求是不一样的.随机森林由于

SLAM概念学习之随机SLAM算法

这一节,在熟悉了Featue maps相关概念之后,我们将开始学习基于EKF的特征图SLAM算法. 1. 机器人,图和增强的状态向量 随机SLAM算法一般存储机器人位姿和图中的地标在单个状态向量中,然后通过一个递归预测和量测过程来估计状态参数.其中,预测阶段通过增量航迹估计来处理机器人的运动,并增加了机器人位姿不确定性的估计.当再次观测到Map中存储的特征后,量测阶段,或者叫更新阶段开始执行,这个过程可以改善整个的状态估计.当机器人在运动过程中观测到新特征时,便通过一个状态增强的过程将新观测的特