雇用问题描述
一个老板想换掉自己的办公助理,并且决定每次面试一个人,如果当前这个面试者比现在的办公助理好,就雇用他,并且解聘现在的办公助理。
描述成伪代码可以有如下形式:
Hire-Assistant(n):
best = 0 //假装有最菜的面试者,其实也可以理解为当前助理最菜
for i=1 to n //遍历全部面试者
interview candidate i //取当前面试者
if candidate i is better than candidate best //判断谁更优秀
best = i //改变best指的人
hire candidate i //雇用面试者i
总共要面试 n 个面试者, 这期间可能会雇用 m 个人,也就是换人换了 m 次。
假设面试一次花费 c 块 ,雇用一个人需要 h 块 ,那么我们可以知道:
面试全部人费用为 C* n ,且这个是固定的。
最后雇用花的费用为 h*m,这个是不确定的。
这时候我们不知道 雇用行为 会出现多少次,这就涉及到概率行为。
概率分析
太多数情况下,我们用概率分析来分析一个算法的运行时间。例如上面 Hire-Assistant中的雇用费用。 为了进行概率分析,我们必须使用或者假设关于输入的分布。 然后分析这个算法,对输入产生的运行时间取平均。在这个问题中可以是对雇用次数取平均或者雇用花费取平均,实际问题实际分析。 我们称这个为平均情况运行时间。
均匀随机队列:面试者出现次序是均匀随机的,每个序列概率都是相等的。
随机算法
如果一个算法的行为不仅由输入决定,还由随机数生成器决定,我们就称这个算法是随机的。 我们假设有一个可以自由使用的随机数生成器 RANDOM(a,b) ,调用它将会等概率返回一个介于 a 和 b 间的整数。在大多数环境中的随机数算法都是这种伪随机数生成器,返回值在统计上看起来是随机的。
当分析一个随机算法的运行时间时,其中输入值由随机算法产生,则运行时间称为期望运行时间。
思考
考虑 RANDOM(a,b)实现,只能调用RANDOM(0,1)
- a 和 b 中有 b - a + 1个数
- RANDOM(a,b)也就是 a + RANDOM(0,b - a + 1)
- 找二进制里 刚好大于 b - a - 1 的数 ,2m >= b - a - 1, 取 m 位
- m位二进制位都由 RANDOM(0,1)生成,若是比 b - a + 1 大,舍掉就行
#include <iostream>
#include <stdlib.h>
#include <ctime>
using namespace std;
//随机生成 0 | 1
int random_0_1()
{
return rand() % 2;
}
//获得刚好大于 b - a + 1 的二进制位数
int getBit(int a, int b)
{
int n = b - a + 1;
int bit = 0;
int value = 1;
while (value < n)
{
bit++;
value = value << 1;
}
return bit;
}
//具体实现
int random_a_b(int a, int b)
{
int bit = getBit(a, b);
int flag;
int result = 0;
while (true)
{
for (int i = 0; i < bit; i++)
{
flag = random_0_1();//二进制位置位
flag = flag << i; //左移到那个位置
result |= flag; //取或
}
if (result + a > b)
{
result = 0;
continue;
}
else
break;
}
return result + a;
}
int main()
{
srand(unsigned(time(NULL)));
for (int i = 0; i < 100; i++)
{
int result = random_a_b(5, 10);
cout << "result: " << result << endl;
}
}
再思考
假设生成 0 的概率为 p,生成1的概率为1-p,怎么制造 RANDOM(a,b)。
设想该生成器随机生成两个数,有下面四种组合:
组合 | 概率 |
---|---|
00 | p2 |
01 | p*(1-p) |
10 | p*(1-p) |
11 | (1-p)2 |
所以能发现 10 和 01 等概率出现,我们令 10 为1 ,01 为0,就能回到上一个思考题做法。
再再思考
已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10。
其实还是想办法找相等概率的数来组合,但是在这里是以和的形式。
令A = rand7 = {1,2,3,4,5,6,7}
令B = (rand7-1)*7 = {0,7,14,21,28,35,,42}
有没有发现什么? A和B中每个元素的概率都是 1/7 ,并且相加后能出现 1~49,在这里构造rand10()只需要舍去 41~49再取余就行了。
指示器随机变量
给定一个样本空间 S 和一个事件 A,那么事件A对应的指示器随机变量 I {A}即:
是不是和我们抛硬币一个道理。
雇用问题与指示器
我们可以定义 n 个变量,分别对应每个面试者是否被雇用。假设 Xi 对应于第 i 个面试者被雇用的指示器随机变量,则有:
而且有 X = X1 + X2 + X3 + … + Xn
当看到前 i 个人时,第 i 个人比 i-1那个优秀的概率 为 1/i ,所以:
最后可以得出 E(X)
也就是大约 雇用了 ln(n)个人。
参考书籍
《算法导论》