随机化算法

随机化算法特征:

对于所求问题的同一实例用同一随机化算法求解两次可能得到完全不同的结果,这两次求解的时间甚至得到的结果可能会有相当大的差别。

 

分类:

1.数值随机化算法

这类算法常用于数值问题的求解,所得到的解往往都是近似解,而且近似解的精度随计算时间的增加不断提高。

使用该算法的理由是:在许多情况下,待求解的问题在原理上可能就不存在精确解,或者说精确解存在但无法在可行时间内求得,因此用数值随机化算法可以得到相当满意的解。

 

示例:计算圆周率Π的值

将n个点随机投向一个正方形,设落人此正方形内切圆(半径为r)中的点的数目为k。

假设所投入的点落入正方形的任一点的概率相等,则所投入的点落入圆内的概率为Π*r2/4*r2=Π/4。当n→∞时,k/n→Π/4,从而Π约等于4*k/n。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2 + 10;
const int INF = 0x3f3f3f3f;
#define m 65536L
#define b 1194211693L
#define c 12345L
class RandomNumber
{
    private:
        unsigned long d;    //d为当前种子
    public:
        RandomNumber(unsigned long s=0);    //默认值0表示由系统自动给种子
        unsigned short random(unsigned long n); //产生0:n-1之间的随机整数
        double fRandom(void); //产生[0,1)之间的随机实数
};
//函数RandomNumber用来产生随机数种子
RandomNumber::RandomNumber(unsigned long s)
{
    if(s==0) d=time(0); //由系统提供随机种子
    else d=s;   //由用户提供随机种子
}
unsigned short RandomNumber::random(unsigned long n)
{
    d=b*d+c;  //用线性同余式计算新的种子d
    return (unsigned short)((d>>16)%n); //把d的高16位映射到0~(n-1)范围内
}
double RandomNumber::fRandom(void)
{
    return random(m)/double(m);
}
double Darts(int n)
{
    static RandomNumber darts;
    int k=0,i;
    double x,y;
    for(int i=1;i<=n;++i)
    {
        x=darts.fRandom();
        y=darts.fRandom();
        if((x*x+y*y)<=1)
            k++;
    }
    return 4.0*k/double(n);
}
int main()
{
    srand(time(NULL));
    //指定运行次数,次数越高精度越高
    printf("%.8lf\n",Darts(10000));
    return 0;
}

 

 

2.蒙特卡罗算法
家特卡罗算法是计算数学中的一 种计算方法,它的基本特点是以概率与统计学中的理论和方法为基础,以是否适合于在计算机上使用为重要标志。蒙特卡罗是摩纳哥的一个著名城市,以赌博闻名于世。为了表明该算法的上述基本特点,蒙特卡罗算法象征性地借用这一.城市的名称来命名。蒙特卡罗算法作为一种可行的计算方法,首先是由Ulam(乌拉姆)和、Neumann(冯 .诺依曼)在 20世纪40年代中叶提出并加以运用,目的是为了解决研制核武器中的计算问题。
该算法用于求问题的准确解。对于许多问题来说,近似解毫无意义。例如,一个判定问题其解为“是”或“否”,二者必居其一,不存在任何近似解答。
蒙特卡罗算法的特点是:它能求得问题的一个解,但这个解未必是正确的。 求得正确解的概率依赖于算法执行时所用的时间,所用的时间越多得到正确解的概率就越高。一般情况下,蒙特卡罗算法不能有效地确定求得的解是否正确。
 
示例:主元素问题
设T[1:n]是一个含有n个元素的数组,当|{i|T[i]等于x}|>n/2时,称元素x是数组T的主元素/对于给定的含有n个元素的数组T,设定确定数组T中是否存在主元素的程序
int majority(int T[],int n)
{
    RandomNumber rnd;
    int i=rnd.random(n)+1;
    int x=T[i];
    //printf("%d %d\n",i,x);
    int k=0;
    for(int j=1;j<=n;++j)
    {
        if(T[j]==x)k++;
    }
    if(k>n/2)
    {
        return x;
    }
    else return -INF;
}
解析:
蒙特卡洛算法对于问题的任一实例得到正确解的概率不低于p(0.5<=p<=1),要想提高p,需要增加majority程序运行次数。我们设得到正确解概率不能低于1-ci(0<ci<=1-p),假设需要调用x次,则p+(1-p)*p+(1-p)2*p+...+(1-p)x-1*p>=1-ci,即1-(1-p)>=1-ci,因为0<1-p<1/2,所以x>=log1-pci,故x=ceil(log2ci/log2(1-p)).
总的来说,ci越接近0越好
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2 + 10;
const int INF = 0x3f3f3f3f;
#define m 65536L
#define b 1194211693L
#define c 12345L
class RandomNumber
{
    private:
        unsigned long d;    //d为当前种子
    public:
        RandomNumber(unsigned long s=0);    //默认值0表示由系统自动给种子
        unsigned short random(unsigned long n); //产生0:n-1之间的随机整数
        double fRandom(void); //产生[0,1)之间的随机实数
};
//函数RandomNumber用来产生随机数种子
RandomNumber::RandomNumber(unsigned long s)
{
    if(s==0) d=time(0); //由系统提供随机种子
    else d=s;   //由用户提供随机种子
}
unsigned short RandomNumber::random(unsigned long n)
{
    d=b*d+c;  //用线性同余式计算新的种子d
    return (unsigned short)((d>>16)%n); //把d的高16位映射到0~(n-1)范围内
}
double RandomNumber::fRandom(void)
{
    return random(m)/double(m);
}
int T[maxn];
int majority(int T[],int n)
{
    RandomNumber rnd;
    int i=rnd.random(n)+1;
    int x=T[i];
    //printf("%d %d\n",i,x);
    int k=0;
    for(int j=1;j<=n;++j)
    {
        if(T[j]==x)k++;
    }
    if(k>n/2)
    {
        return x;
    }
    else return -INF;
}
int majorityMC(int T[],int n,double ci)
{
    int k=(int)ceil(log(ci)/log(0.5));
    printf("%d\n",k);
    for(int i=1;i<=k;++i)
    {
        int tmp=majority(T,n);
        if(tmp!=-INF)
            return tmp;
    }
    return -INF;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&T[i]);
    }
    int tmp=majorityMC(T,n,0.09);
    printf("%d\n",tmp);
    return 0;
}

 

3.拉斯维加斯算法
该算法绝不返回错误的解,也就是说,使用拉斯维加斯算法不会得到不正确的解,-旦找到一个解,那么这个解肯定是正确的。但是有时候拉斯维加斯算法可能找不到解。
与蒙特卡罗算法类似,拉斯维加斯算法得到正确解的概率随着算法执行时间的增加而提高。对于所求解问题的任一实例,只要用同一 -拉斯维加斯算法对该实例反复求解足够多的次数,可使求解失效的概率任意小。
 
给一个分解给定整数因子的程序

 

偷个懒(嘻嘻 

 
4.舍伍德算法
当一个确定性算法在最坏情况下的计算时间复杂性与其在平均情况下的计算复杂性有较大差异时,可在这个确定性算法中引/人随机性来降低乐最坏情况出现的概率,进面消除或减少问题好坏实例之间的这种差异,这样的随机化算法称为舍伍德算法,因此,含伍德算法不会改变对应确定性算法的求解结果,;每次运行于都能够得到问题的解,并且所得到的解是正确情况的发生,而是降低最坏情况发生的概率。故而,舍伍德算法不改变原有算法的平均性能,只是设法保证以更高概率获得算法的平均计算性能。
这个算法的实例也就是快速排序中加入了随机选取标准值增快了速度
  

 -------------------------------------------------------------------------------------------------------------

一、随机排列数组

随机排列要求对于数组中每一个元素出现到任意一个位置的概率为1/n(数组长度为n)

伪代码:

RANDOMIZE-IN-PLACE ( A , n )
     for i ←1 to n
          do swap A[i] ↔A[RANDOM(i , n )]

证明:

A[1]位于位置1的概率为1/n,这个显然,因为A[1]不被1到n的元素替换的概率为1/n,而后就不会再改变A[i]了。而A[1]位于位置2的概率也是1/n,因为A[1]要想位于位置2,则必须在第一次与A[k]交换(k=2...n),同时第二次A[2]与A[k]替换,第一次与A[k]交换的概率为(n-1)/n,而第二次替换概率为1/(n-1),所以总的概率是(n-1)/n * 1/(n-1) = 1/n。同理可以推导其他情况。

当然这个条件只能是随机排列数组的一个必要条件,也就是说,满足元素A[i]位于位置j的概率为1/n不一定就能说明这可以产生随机排列数组。因为它可能产生的排列数目少于n!,尽管概率相等,但是排列数目没有达到要求。

但是上面这个算法RANDOMIZE-IN-PLACE可以产生均匀随机排列,证明过程见:https://blog.csdn.net/sgbfblog/article/details/7917685

 

二、随机选取给定整数流的一个数字

整数流也就是由数字构成的连续序列,这个也要保证整数流每一个位置的数字取到的概率相等

解:

如果数据流长度为1,那么必选第1个数字。

如果数据流长度为2,那么我们选第2个数字的概率为1/2,我们以1/2的概率用第2个数字替换前面选的随机数,得到新的随机数。

.........

如果数据流长度为n,那么我们选择第n个数字的概率为1/n,即我们以1/n的概率用第n个数字替换前面选的随机数,得到新的随机数。

一个简单的方法就是使用随机函数f(n)=bigrand()%n,其中bigrand()返回很大的随机整数,当数据流到第n个数时,如果f(n)==0,则替换前面的已经选的随机数,这样可以保证每个数字被选中的概率都是1/n。如当n=1时,则f(1)=0,则选择第1个数,当n=2时,则第2个数被选中的概率为1/2,以此类推,当数字长度为n时,第n个数字被选中的概率为1/n。

 

三、随机从n个数里面选取m个数

代码:

void genknuth(int m, int n)
{ 
        for (int i=0; i<n; i++) //必定会选取m个数,当n-i==m的时候,那么对于区间[i,n]每一个数都会被选取
            if (bigrand() % (n-i) < m) {  //n-i中i每次加1,相当于remaining每次减1
                 cout << i << endl;
                 m--;  //选取的数目减1
             }
}

先考虑个简单的例子,当m=2,n=5时,我们需要从0~4这5个整数中等概率的选取2个有序的整数,且不能重复。如果采用如下条件选取:bigrand() % 5 < 2,则我们选取0的概率为2/5。但是我们不能采取同样的概率来选取1,因为选取了0后,我们应该以1/4的概率来选取1,而在没有选取0的情况下,我们应该以2/4的概率选取1。

-------------------------------------------------------------------------------------------------------------

 

posted @ 2020-12-08 21:41  kongbursi  阅读(1819)  评论(0编辑  收藏  举报