蓄水池算法(随机取数)

蓄水池算法

情景:

给一堆数(不知道个数,就是不能随机一个下标取数),从中选择一个数,要求每个数的概率为 1 / n 1/n

算法:

对于第 i i 个数,有 1 / i 1/i 的概率替换最终答案。此时每个数,设第m个数,其作为最终答案的概率P为:

在这里插入图片描述
选这个数,且后面所有数都不选。得出每个数的概率为 1 / n 1/n


扩展

情景:

给一堆数(不知道个数,就是不能随机一个下标取数),从中选择K个数,要求每个数的概率为 K / n K/n

算法:

先选前K个,对于之后的第 i i 个数,有 K / i K/i 的概率取(随机替换原来的数),最后第m个数取的概率P为:
在这里插入图片描述
选这个数,且后面所有数要么不选,要么选且没有替换这个数。得出每个数的概率为 K / n K/n


代码

/*
 *  Author : Jk_Chen
 *    Date : 2020-04-08-11.30.23
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/

int randChoose(vector<int>&V){
    int idx=0;
    int ans=V[0];
    for(auto P:V){
        // 1/idx
        if(rand()%(idx+1)==0)ans=P;
        idx+=1;
    }
    return ans;
}

vector<int> randChoose(vector<int>&V,int k){
    assert(V.size()>=k);
    vector<int>res(k);
    rep(i,0,k-1)res[i]=V[i];
    rep(i,k,V.size()-1){
        // k/idx
        if(rand()%(i+1)<k){
            int pos=rand()%k;
            res[pos]=V[i];
        }
    }
    return res;
}

void testRandChooseOne(){
    srand(time(0));
    vector<int>V(100);
    rep(i,0,99)V[i]=i;
    int cnt[100];
    mmm(cnt,0);
    rep(i,1,10000){
        cnt[randChoose(V)]++;
    }
    rep(i,0,99)printf("%d\n",cnt[i]);
}

void testRandChooseK(){
    srand(time(0));
    vector<int>V(100);
    rep(i,0,99)V[i]=i;
    int cnt[100];
    mmm(cnt,0);
    rep(i,1,10000){
        auto res=randChoose(V,3);
        for(auto P:res)cnt[P]++;
    }
    rep(i,0,99)printf("%d\n",cnt[i]);
}

int main(){
    testRandChooseOne();
    testRandChooseK();
    return 0;
}

/*_________________________________________________________end*/

发布了790 篇原创文章 · 获赞 348 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/105384147