蓄水池抽样算法

题目描述:从n个元素抽取k个元素,使得每个元素被抽取的概率相同

思路:按照蓄水池抽样算法,先将n个元素的前k个元素加入到被抽取的集合中,再从i=k+1开始遍历,每次从1-i之间随机取一个数m,若该数m小于等于k,则将当前第i个数替换掉被抽取的集合中第m个数,遍历结束后,被抽取的集合即为所求

证明:

使用数学归纳法,若n=k时,显然成立

当n=m时成立,对于n=m+1,已知对前m个数可以做到使每个数被等概率抽取,即每个数被抽取的概率为

k/m,对于i=m+1,从1-m+1之间随机取一个数s,则第m+1个数被抽取的概率为k/m+1(即当s<=k时),前m个数中的数被抽取的概率为(k/m)*(m/(m+1))=k/(m+1),i=m+1成立

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,k;
int a[100];
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
srand(time(0));
for(int i=k+1;i<=n;i++){
int m=rand()%i+1;
if(m<=k){
a[m]=a[i];
}
}
cout<<"所求的k个数为:";
for(int i=1;i<=k;i++){
cout<<a[i]<<" ";
}
cout<<endl;

return 0;
}
,