概率算法(算法分析与设计)

来源:互联网 发布:windows http代理软件 编辑:程序博客网 时间:2024/06/04 19:42

0.概论

包括四种算法,数值概率算法(数值问题的求解,最优化问题的近似解)、蒙特罗卡算法(判定问题的准确解,不一定正确)、拉斯维加斯算法(不一定会得到解,但得到的解一定是正确解)、舍伍德算法(总能求得一个解,且一定是正确解)。

1.随机数

随机数生成,线性同余法


d 为用户输入随机数;m 足够大,一般为最大机器数;b为一质数;c>=0

2.舍伍德算法(对输入进行处理,使得计算时间复杂度对所有实例相对均匀)

这篇写的很好:http://www.cnblogs.com/hxsyl/p/3219621.html

其实就是在确定性算法中引入随机性。其优点是其计算时间复杂性对所有实例而言相对均匀,但与其相应的确定性算法相比,其平均时间复杂度没有改进。

如一般快速排序都是以第一个元素作为基准元素,而舍伍德版的快速排序是随机选择一个元素作为基准元素(代码见章二分治学习记录)。那么当一个确定性算法无法直接改造成舍伍德版本的时候,就可以对输入进行洗牌。以下是洗牌算法(O( n ))

#include<iostream>#include<algorithm>#include<cstdlib>#include<vector>using namespace std;int random(int e){return rand()%e;}template <class T> void shuffle(vector<T> &x){int num=x.size();for(int i=0;i<num;i++){int j=random(num-i)+i;//产生一个大于i的数 swap(x[i],x[j]);}}
概率算法的一个特点是对同一实例多次运用同一概率算法结果可能不同。舍伍德算法总能求的问题的一个正确解,当一个确定性算法在最坏情况和平均情况下差别较大时可在这个确定性算法中引入随机性将之改造成一个舍伍德算法;引入随机性不是为了消除最坏,而是为了减少最坏和特定实例的关联性。

跳跃表

有序链表S,搜索其中一个元素需要花费线性时间。为提高搜索效率,可以在部分节点上增设附加指针,这种向前附加指针的有序链表称为跳跃表

完全跳跃表,如(c)所示,每个k级节点都有k+1个指针,分别跳过2^k-1,2^(k-1)-1,...,2^0-1个中间结点,完全跳跃表与完全二叉树一样,插入和删除会破坏它的平衡性,用舍伍德随机的思想,在插入节点上以概率1/2引入1级指针,概率1/4引入2级指针,....

3.我们把随机算法分成两类:

    • 蒙特卡罗算法:采样越多,越近似最优解;
    • 拉斯维加斯算法:采样越多,越有机会找到最优解;
    • 这两类随机算法之间的选择,往往受到问题的局限。如果问题要求在有限采样内,必须给出一个解,但不要求是最优解,那就要用蒙特卡罗算法。反之,如果问题要求必须给出最优解,但对采样没有限制,那就要用拉斯维加斯算法。对于机器围棋程序而言,因为每一步棋的运算时间、堆栈空间都是有限的,而且不要求最优解,所以ZEN涉及的随机算法,肯定是蒙特卡罗式的。

4.拉斯维加斯算法

而拉斯维加斯算法,则是另一种情况。假如有一把锁,给我100把钥匙,只有1把是对的。于是我每次随机拿1把钥匙去试,打不开就再换1把。我试的次数越多,打开(最优解)的机会就越大,但在打开之前,那些错的钥匙都是没有用的。这个试钥匙的算法,就是拉斯维加斯的——尽量找最好的,但不保证能找到。

拉斯维加斯算法的一个显著的特征是:它所做的随机性决策有可能导致算法找不到所需的解。拉斯维加斯算法不一定能够得到解,但如果得到了,那一定是正确解

nQueen拉斯维加斯+回溯

#include<iostream>#include<vector>#include<cmath>#include<cstdlib>using namespace std;vector<int> x;//临时存放,x[i]=j表示在第i行,第j列放置皇后vector<int> y;//最终数组 bool flag=true;int random(int n){return rand()%n;}bool place(int k){for(int i=0;i<k;i++){if(abs(x[i]-x[k])==abs(i-k)||x[k]==x[i]){return false;}}return true;} void backtrack(int k){if(k>=x.size()){flag=false;for(int i=0;i<x.size();i++){y[i]=x[i];cout<<x[i]<<"\t";}cout<<endl;return;}else{for(int i=0;i<x.size();i++){x[k]=i;if(place(k)){backtrack(k+1);}}}}bool queenLV(int num)//num之前用拉斯维加斯 {int k=0;int count=1; while((k<num)&&(count>0)){count=0;vector<int> y1;//保存可用列 for(int i=0;i<=num;i++){x[k]=i;if(place(k))//可以放置 {y1.push_back(i);count++;}}if(count>0)//可用列个数大于0 {int j=random(count);x[k++]=y1[j];//随机选择一个可用列 }}return count>0;}void nQueen(int num,int xxx){for(int i=0;i<num;i++){x.push_back(-1);y.push_back(-1);}while(!queenLV(xxx)){cout<<"GAN!"<<endl;} backtrack(xxx);} int main(){int num;int xxx;cin>>num>>xxx;nQueen(num,xxx);}
不一定能产生解吧。如queenLV产生(1,5,2,6,3,0,4)时符合要求,这时每列都被占,backtrack只能选择列7,但是| 7 - 2 |==| x[ 7 ] - x[ 2 ] |。

一种确定性算法,在应用了像这样随机放解(random assignment)的情况,就称为应用了拉斯维加斯思想。如0-1背包问题,物品i可放,可不放,通过random(0,1)来决定此物品的存放与否。

5.蒙特卡罗算法

写的很好:http://www.zhihu.com/question/20254139?utm_campaign=rss&utm_medium=rss&utm_source=rss&utm_content=title

举个例子,假如筐里有100个苹果,让我每次闭眼拿1个,挑出最大的。于是我随机拿1个,再随机拿1个跟它比,留下大的,再随机拿1个……我每拿一次,留下的苹果都至少不比上次的小。拿的次数越多,挑出的苹果就越大,但我除非拿100次,否则无法肯定挑出了最大的。这个挑苹果的算法,就属于蒙特卡罗算法——尽量找好的,但不保证是最好的。

定义为:计算机模拟,从总体抽取大量随机样本的计算方法统称为蒙特罗卡方法。

查了网上的例子,看着都像是数值概率算法的例子。构造一个随机分布(可以是离散的,连续的),是这个随机分布的某些数字特征等于所求的东西,或通过中心极限定理,大数定理等是这些数字特征与所求的东西挂上钩,然后通过数字特征求解出一个近似解来。与数值概率算法不同的是,蒙特罗卡考虑到了解的真假性,置信程度

A.数值概率算法

a.随机投点法(以求定积分为例)


b.平均值法(以求定积分为例)

基本思想:构造一个随机变量分布使其期望(这样就可以直接相加除以n了)等于问题所求的值、对这个概率分布进行抽样、用样本的均值作为问题所求值的估计。


0 0
原创粉丝点击