随机算法-简单来一发

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

目录


随机数函数

srand((unsigned)time(0));
int tmp = rand()%m+1;


随机生成数组

unsigned int x,y,z;
inline unsigned int tang(){
  unsigned int t;
  x ^= x<<16;
  x ^= x>>5;
  x ^= x<<1;
  t=x;
  x=y;
  y=z;
  z=t^x^y;
  return z;
}


随机乱序

CF Round492 Div2 的E的可以用这个函数水过去。要不是fst我也知道有这种骚操作

for(int i=0;i<n;++i)cout<<cw[i]<<" ";
cout<<"\n";

random_shuffle(cw,cw+n);//cw数组已被随机乱序

for(int i=0;i<n;++i)cout<<cw[i]<<" ";
cout<<"\n";


nth_element函数

API文档
例题:hdu6040

nth_element(cw,cw+len,cw+n);
//下标为len位置的值是这个数组的第len小。
//小于它的都在其前面,大于它的都在其后面,但不保证有序!

// nth_element example
#include <iostream>     // std::cout
#include <algorithm>    // std::nth_element, std::random_shuffle
#include <vector>       // std::vector

bool myfunction (int i,int j) { return (i<j); }

int main () {
  std::vector<int> myvector;

  // set some values:
  for (int i=1; i<10; i++) myvector.push_back(i);   // 1 2 3 4 5 6 7 8 9

  std::random_shuffle (myvector.begin(), myvector.end());

  // using default comparison (operator <):
  std::nth_element (myvector.begin(), myvector.begin()+5, myvector.end());

  // using function as comp
  std::nth_element (myvector.begin(), myvector.begin()+5, myvector.end(),myfunction);

  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}


随机选取k个数

bool getRand(const vector vecData, int m, vector& vecRand){
  int nSize = vecData.size();
  if(nSize  < m || m < 0)return false;
  vecRand.clear();
  vecRand.reserve(m);
  for(int i = 0, isize = nSize; i < isize ; ++i){
    double fRand = frand();
    if(fRand <= m*1.0/nSize){
      vecRand.push_back(vecData[i]);
      --m;
    }
    --nSize;
  }
  return true;
}



 最近在看王晓东的《计算机算法设计与分析(第3版) 》,感觉讲的挺不错的。这里先推荐下。

 接下来的几章(包括本章),我准备以连载的方式讲出来,主要用到的资料是上面推荐的那本书以及《算法导论》和网上的资源,内容是概率分析与随机算法。文章内大部分内容出自书中,我仅以汇总形式以及个人理解加以补充。如有纰漏,欢迎指出。

 概率算法的一个基本特征是对所求解问题的同一实例用同一概率算法求解两次可能得到完全不同的效果。这两次求解问题所需的时间甚至所得到的结果可能会有相当大的差别。一般情况下,可将概率算法大致分为四类:数值概率算法,蒙特卡罗(Monte Carlo)算法,拉斯维加斯(Las Vegas)算法和舍伍德(Sherwood)算法。

 随机数在概率算法设计中扮演着十分重要的角色。在现实计算机上无法产生真正的随机数,因此在概率算法中使用的随机数都是一定程度上随机的,即伪随机数。

产生随机数最常用的方法是线性同余法。由线性同余法产生的随机序列a1,a2,…,an满足
1.a0=d
2.an=(b*an-1+c)mod m (n=1,2…….)
其中,b>0, c>=0, d>=m。d称为该随机序列的种子。

一般情况下,取gcd(m, b)=1,因此可取b为一素数。
这是一个随机数类

const unsigned long maxshort = 65535L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;

class RandomNumber{
private:
    // 当前种子
    unsigned long randSeed;
public:
    // 构造函数,默认值0表示由系统自动产生种子
    RandomNumber(unsigned long s = 0);
    // 产生0 ~ n-1之间的随机整数
    unsigned short Random(unsigned long n);
    // 产生[0, 1) 之间的随机实数
    double fRandom();
};

// 产生种子
RandomNumber::RandomNumber(unsigned long s){
    if(s == 0)
        randSeed = time(0);    //用系统时间产生种子
    else
        randSeed = s;
}
// 产生0 ~ n-1 之间的随机整数
unsigned short RandomNumber::Random(unsigned long n){
    randSeed = multiplier * randSeed + adder;
    return (unsigned short)((randSeed >> 16) % n);
}
// 产生[0, 1)之间的随机实数
double RandomNumber::fRandom(){
    return Random(maxshort) / double(maxshort);
}

利用这个随机数类,写一个程序,模拟抛硬币的实验。

抛10次硬币构成一个事件,每次事件记录得到正面的个数。反复模拟这个事件50,000次,然后对这50,000L次进行输出频率图,比较每次事件得到正面次数的比例。

以下是总的代码:
头文件 RandomNumber.h:

// RandomNumber.h
const unsigned long maxshort = 65535L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;

#ifndef RANDOMNUMBER_H
#define RANDOMNUMBER_H

class RandomNumber{
private:
    // 当前种子
    unsigned long randSeed;
public:
    // 构造函数,默认值0表示由系统自动产生种子
    RandomNumber(unsigned long s = 0);
    // 产生0 ~ n-1之间的随机整数
    unsigned short Random(unsigned long n);
    // 产生[0, 1) 之间的随机实数
    double fRandom();
};

#endif

类实现文件RandomNumber.cpp :

// RandomNumber.cpp
#include "RandomNumber.h"
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
// 产生种子
RandomNumber::RandomNumber(unsigned long s){
    if(s == 0)
        randSeed = time(0);    //用系统时间产生种子
    else
        randSeed = s;
}

// 产生0 ~ n-1 之间的随机整数
unsigned short RandomNumber::Random(unsigned long n){
    randSeed = multiplier * randSeed + adder;
    return (unsigned short)((randSeed >> 16) % n);
}

// 产生[0, 1)之间的随机实数
double RandomNumber::fRandom(){
    return Random(maxshort) / double(maxshort);
}

主文件Main :

 // 主文件main
/*
* Author: Tanky woo
* Blog:   www.WuTianQi.com
* Date:   2010.12.7
* 代码来至王晓东《计算机算法设计与分析》
*/
#include "RandomNumber.h"
#include <iostream>
#include <iomanip>
#include <time.h>
using namespace std;
int TossCoins(int numberCoins){
    // 随机抛硬币
    static RandomNumber coinToss;
    int i, tosses = 0;
    for(i = 0; i < numberCoins; ++i)
        tosses += coinToss.Random(2);
    return tosses;
}
int main(){
    // 模拟随机抛硬币事件
    const int NCOINS = 10;
    const long NTOSSES = 50000L;
    // heads[i]得到的i次正面的次数
    long i, heads[NCOINS+1];
    int j, position;
    // 初始化数组heads
    for(j = 0; j < NCOINS+1; ++j)
        heads[j] = 0;
    // 重复50,000次模拟事件
    for(i = 0; i < NTOSSES; ++i)
        heads[TossCoins(NCOINS)] ++;
    // 输出频率图
    for(i = 0; i <= NCOINS; ++i){
        position = int (float(heads[i]) / NTOSSES*72);
        cout << setw(6) << i << " ";
        for(j = 0; j<position-1; ++j)
            cout << " ";
        cout << "*" << endl;
    }
    return 0;
}  

这里写图片描述
此部分内容转载:here


猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81410816