從 5個元素中取3個數排列。第一次取有5種情況,拿出乙個數後,第二次取有4種情況,第三次取有3中情況。所以5中取3的排列共有
5*(5-1)(5-2) = 60種情況,由 3個數的排列由32*1=6中。也就是每一種組合有6種排列。
所以中取三個數的組合為
5 ∗(
5−1)
∗(5−
2)3∗
(3−1
)(3−
2)=10
\frac = 10
3∗(3−1
)(3−
2)5∗
(5−1
)∗(5
−2)
=10推廣到一般情況,從n個元素中取k個元素的組合個數,記作c(n,k),則有
c (n
,k)=
n∗(n
−1)∗
(n−2
)...
∗(n−
(k−2
))∗(
n−(k
−1))
k∗(k
−1)∗
(k−2
)...
∗3∗2
∗1
c(n,k) = \frac
c(n,k)
=k∗(
k−1)
∗(k−
2)..
.∗3∗
2∗1n
∗(n−
1)∗(
n−2)
...∗
(n−(
k−2)
)∗(n
−(k−
1))
其中,含有某個元素m的組合個數,取出m後,還剩n-1個元素,從中要抽取另外k-1個元素,和m組成組合。所以c(n,k)個組合中含有某個確定元素m的組合個數為c(n-1,k-1),那麼對於n個元素取出k個元素,某個元素被抽中的概率
p =c
(n−1
,k−1
)c(n
,k)=
kn
p = \frac = \frac
p=c(n,
k)c(
n−1,
k−1)
=nk
123
456…
kk+1
…n-1
n使用均勻隨機數生成函式rand(),從n個元素中抽取k個元素。要求每個元素被抽中的概率符合k
n\frac
nk為了便於理解,下面的說明違背了程式編寫的傳統,陣列索引不從0開始,而從1起始。
從第k+1個元素開始處理,
第k+1個元素,int index = rand()%(k+1) + 1; index的取值範圍是[1,k+1],如果 index 的取值在[1,k]上,則 把第k+1個元素與index位置的元素交換。這個事件發生的概率為kk+index121\frac
k+1k
第k+2個元素,int index = rand()%(k+2) + 1; index的取值範圍是[1,k+2],如果 index 的取值在[1,k]上,則 把第k+2個元素與index位置的元素交換。這個事件發生的概率為kk+
2\frac
k+2k
第k+3個元素,int index = rand()%(k+3) + 1; index的取值範圍是[1,k+3],如果 index 的取值在[1,k]上,則 把第k+3個元素與index位置的元素交換。這個事件發生的概率為kk+
3\frac
k+3k…
…第n-1個元素,int index = rand()%(n-1) + 1; index的取值範圍是[1,n-1],如果 index 的取值在[1,k]上,則 把第n-1個元素與index位置的元素交換。這個事件發生的概率為kn−
1\frac
n−1k
第n個元素,int index = rand()%(n) + 1; index的取值範圍是[1,n],如果 index 的取值在[1,k]上,則 把第n個元素與index位置的元素交換。這個事件發生的概率為k
n\frac
nk
3456
…kk+1…
n-1npkk+
1\frac
k+1kkn−
1\frac
n−1kkn−
2\frac
n−2k
證明,經過這輪操作後,n個元素中每個元素在前k個的概率均符合要求,分兩種情況討論。
1,索引為m的元素,m<=k,想要在處理後仍然在前k個,必須滿足,所有的隨機生成int index全不為m,淘汰是個單向過程,一旦被從前k個剔除,就無法回到前k個中。所以
p =k
k+1∗
k+1k
+2∗k
+2k+
3∗n−
2n−1
∗n−1
n=kn
p = \frac *\frac *\frac *\frac * \frac = \frac
p=k+1k
∗k+
2k+1
∗k+
3k+2
∗n−
1n−2
∗nn
−1=
nk
2,索引為m的元素,m>k,在處理前不在前k個元素,所以它被抽中必須要滿足處理到它時的計算出的index值小於等於k,這樣m元素就被交換到了前k個,且在處理後面的元素是,m元素沒被交換出去。
p =k
m∗mm
+1∗m
+1m+
2∗n−
2n−1
∗n−1
n=kn
p = \frac *\frac *\frac *\frac * \frac = \frac
p=mk∗
m+1m
∗m+
2m+1
∗n−
1n−2
∗nn
−1=
nk證的,n中某個任意元素經過這個操作,位置在k前個的概率等於,n個元素取出k個元素,某個元素被抽中的概率。
#include #include using namespace std;
const int n = 1000;
const int k = 100;
int main(int argc, char *ar**)
for(int i=k;i}
for(int i=0;ireturn 0;
}
蓄水池 抽樣
蓄水池抽樣問題描述的是,在乙個無窮盡的樣本中,要求隨即抽取一些樣本,這些樣本被抽取到的概率必須保持一致。乙個蓄水池就可以理解為無窮大的樣本空間。解決方案就是蓄水庫抽樣 reservoid sampling 主要思想就是保持乙個集合,作為蓄水池,依次遍歷所有資料的時候以一定概率替換這個蓄水池中的數字。...
蓄水池抽樣
題目 要求從n個元素中隨機的抽取k個元素,其中n無法確定 解法 首先選擇n中的前k個數加入 蓄水池 中,然後從第k 1個數開始,以k k i i 1,2,3.的概率選擇這個數,然後在蓄水池中隨機選擇乙個數,並將其替換,n個元素遍歷完畢後,蓄水池中的k個數就是隨機選擇的。證明 這裡即需要證明每個數出現...
蓄水池抽樣
給定乙個長度很長的資料流,在處理完成之前不知道其具體長度,如何在遍歷一遍資料流的情況下,隨機地抽出m個不重複的資料。key words 長度很長,遍歷完之前不可知 o n 複雜度 等概率地抽出m個數,每個數被抽中的概率為m n。如果接收的資料量小於m,直接放入蓄水池reservoir如果接收的數量大...