简介:
一个随机化算法( randomized algorithm) 是指需要利用随机数发生器的算法,算法执行的某些选择依赖于随机数发生器所产生的随机数。
随机化算法有时也称概率算法( probabilisticalgorithm),但也有人对两者这样区分:如果取得结果的途径是随机的,则称为随机算法,如拉斯维加斯算法;而如果取得的解是否正确存在随机性,称为概率算法,如蒙特卡罗算法。
- 分治、动态规划、贪心法、回溯和分支限界等算法的每一计算步骤都是确定的,概率算法允许执行过程中随机选择下一计算步骤。
- 在多数情况下,当算法在执行过程中面临一个选择时,随机性选择常比最优选择省时,因此概率算法可在很大程度上降低算法复杂性。
- 概率算法的一个基本特征是对所求解问题的同一实例用同一概率算法求解两次可能得到完全不同的效果(所需时间或计算结果)。
算法分类
- 数值随机化算法求解数值问题的近似解,精度随计算时间增加而不断提高。
- 舍伍德算法消除算法最坏情况行为与特定实例之间的关联性,并不提高平均性能,也不是刻意避免算法的最坏情况行为。
- 拉斯维加斯算法求解问题的正确解,但可能找不到解。
- 蒙特卡罗算法求解问题的准确解,但这个解未必正确,且一般情况下无法有效判定正确性。
随机化算法的特点
1.当算法执行过程中面临选择时,概率算法通常比最优选择算法省时。
2.对所求问题的同一实例用同一概率算法求解两次,两次求解所需的时间甚至所得的结果可能有相当大的差别。
舍伍德算法:
总能求得问题的正确解。当一个确定性算法在最坏情况下的计算复杂度与其在平均情况下的计算复杂度两者相差较大时,可以在这个确定算法中引入随机性将它改造成一个舍伍德算法,用来消除或减少问题的不同实例之间在计算时间上的差别。舍伍德算法的精髓丕是避免算法的最坏情况行为,而是设法消除这种最坏行为与特定实例之间的关联性。
蒙特卡罗算法:
该法用于求问题的准确解(或者说是精确解而不是近似解),但不保证所求得的解是正确的,也就是说,蒙特卡罗算法求得的解有时是错误的。不过,由于可以设法控制这类算法得到错误解的概率,并因它的简单高效,是很有价值的一类随机算法。
拉斯维加斯算法:
求得的解总是正确的,但有时拉斯维加斯算法可能始终找不到解。一般情况下,求得正确解的概率随计算时间的增加而增大。因此,为了减少求解失败的概率,可以使用一个拉斯维加斯算法对同一实例,重复多次执行该算法。
随机数
在现实计算机上无法产生真正的随机数,因此在随机化算法中使用的随机数都是一定程度上随机的,即伪随机数。(线性同余)
例子:
①求圆周率
double Darts(int n)
{
//用随机投点法计算r值
static RandomNumber dart;
int k=0;
for (int i=1;i < =n;i++)
{
double x=dart.fRandom();
double y=dart.fRandom();
if ((x*x+y*y)<=1) k++;
}
return 4*k/double(n);
}
②计算定积分
double Darts(int n){//用随机投点法计算定积
static RandomNumber dart;
int k=0;
for (int i=1;i<=n;i++) {
double x=dart.fRandom();
double y=dart.fRandom();
if (y<=f(x)) k++;
}
return k/double(n);
}
③求解非线性方程组
函数极小值法:
在求根区域D内,选定随机点x作为随机搜索的出发点。
1.按照预先选定的分布(正态分布、均匀分布等),逐个选取随机点x,计算目标函数,满足精度要求的随机点就是近似解。
2.在算法的搜索过程中,假设第j步随机搜索得到的随机搜索点为x。在第j+1步,生成随机搜索方向和步长,计算出下一步的增量△xi。从当前点xi依△x,得到第j+1步的随机搜索点。当中
时,取为所求韭线性方程组的近似解。否则进行下一步新的随机搜索过程
while((min > epsilon)&&( < Steps)){ //计算随机搜索步长因子
if (fx < min){搜索成功,增大步长因子
min=fx;//fx为目标函数值,min为当前最优值
a*= k;// a为步长因子
success = true;
}
else{/l搜索失败,减少步长因子
mm++;
if(mm> M a/= k; success = false;}
for(inti=1;i<n;i++)//计算随机搜索方向和增量
r[i]| = 2.0 * rnd.fRandom() - 1;/r为搜索方向向量
if (success)
for(int i=1; i<= n; i++)dx[i]=a * r[i];
else
for(int i=1;i <n; f+)
dxi= a* r[i];
舍伍德算法
设A是一个确定性算法,当它的输入实例为x时所需的计算时间记为tA(x)。设X,是算法A的输入规模为n的实例的全体,则当问题的输入规模为n时,算法A所需的平均时间为:
这显然不能排除存在x∈Xn使得tA(x)>>tA‘(n)的可能性。希望获得一个随机化算法B,使得对问题的输入规模为n的每个实例均有:
tB(x)=tA'(n)+ s(n)
这就是舍伍德算法设计的基本思想。
当s(n)与tA(n)相比可忽略时,舍伍德算法可获得很好的平均性能。
有时也会遇到这样的情况,即所给的确定性算法无法直接改造成舍伍德型算法。此时可借助于随机预处理技术,不改变原有的确定性算法,仅对其输入进行随机洗牌,同样可收到舍伍德算法的效果。
/*例如,对于确定性选择算法,可以用下面的洗牌算法shuffle将
数组a中元素随机排列,然后用确定性选择算法求解。这样做所
收到的效果与舍伍德型算法的效果是一样的。
*/
template<class Type>
void Shuffle(Type a[], int n){//随机洗牌算法
static RandomNumber rnd;
for (int i=0;i<n;i++)
{
int j=rnd.Random(n-i)+i;
Swap(a[i], a[j]);
}
}
跳跃表
●舍伍德型算法的设计思想还可用于设计高效的数据结构。
●如果用有序链表来表示一个含有n个元素的有序集S,则在最坏情况下,搜索S中一个元素需要2(n)计算时间。
●提高有序链表效率的一个技巧是在有序链表的部分结点处增设附加指针以提高其搜索性能。在增设附加指针的有序链表中搜索一个元素时,可借助于附加指针跳过链表中若干结点,加快搜索速度。这种增加了向前附加指钍的有序链表称为跳跃表
完全跳跃表与完全二叉搜索树的情形非常类似。它虽然可以有效地支持成员搜索运算,但不适应于集合动态变化的情况。集合元素的插入和删除运算会破坏完全跳跃表原有的平衡状态,影响后继元素搜索的效率。
为了在动态变化中维持跳跃表中附加指针的平衡性,必须使跳跃表中k级结点数维持在总结点数的一定比例范围内。注意到在一个完全跳跃表中,50%的指针是0级指针;25%的指针是1级指针; ... (100/2k+1)%的指针是k级指针。因此,在插入-一个元素时,以概率1/2引入一个0级结点,以概率1/4引入-一个1级结点,...以概率1/2k+1引入一个k级结点。
另一方面,二个i级结点指向下一个同级或更高级的结点,它所跳过的体点数不再准确地维持在2-1。经过这样的修改,就可以在插入或删除一个元素时,通过对跳跃表的局部修改来维持其平衡性。
在一个完全跳跃表中,具有i级指针的结点中有一半同时具有i+1级指针。为了维持跳跃表的平衡性,可以事先确定一个实0≤p<1,并要求在跳跃表中维持在具有i级指针的结点中同时具有计1级指针的结点所占比例约为p.为此目的,在插入一个新结点时,先将其结点级别初始化为0,然后用随机数生成器反复地产生一个[0,1]间的随机实数q。如果qsp,则使新结点级别增加1,直至q≥p。
拉斯维加斯算法:
//拉斯维加斯算法的一个显著特征是它所作的随机性决策有可能导致算法找不到所需的解。
void obstinate(Object x, Object y){//反复调用拉斯维加斯算法LV(x,y),直到找到问题的一个解y
bool success= false;
while (!success)
success=lv(x,y);
}