隨機化算法特征:
對於所求問題的同一實例用同一隨機化算法求解兩次可能得到完全不同的結果,這兩次求解的時間甚至得到的結果可能會有相當大的差別。
分類:
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; }
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; }
#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; }

偷個懶(嘻嘻
-------------------------------------------------------------------------------------------------------------
一、隨機排列數組
隨機排列要求對於數組中每一個元素出現到任意一個位置的概率為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。
-------------------------------------------------------------------------------------------------------------