Re: [心得] 亂數不重複的方法

看板C_and_CPP (C/C++)作者 (眠月)時間16年前 (2010/02/13 08:10), 編輯推噓4(404)
留言8則, 4人參與, 最新討論串2/3 (看更多)
假設要從十張裡面抽出三張 我們就知道每張牌被抽出來的機率是 3/10 所以就可以這樣寫 for ( size_t i=0; i<10; ++i ) { if ( rand() % 10 < 3 ) { // 小於 3 代表被選中 cout << i ; } } 但是這樣有個問題是,被選出來的不一定是三張, 可能是 0 張,也可能是 10 張,雖然說平均是 3 張沒錯。 所以我們要在這個過程控制一下,試考慮一個狀況: 當我第一張的 rand()%10 就小於 3 被選中, 那剩下的 9 張裡面其實只能有兩張被選中, 所以之後的每張牌其實機率就不是 rand()%10 < 3, 而是 rand()%9 < 2,因為剩下的九張牌裡面每個人中獎的機會是 2/9。 又,假設繼續選選選選到第 9 張,總共有兩張被選中, 還有一張沒出來,那最後一張被選中的機率就一定會是 1/1。 利用這種機率控制的方法,就可以讓抽完的牌數一定是 3。 所以我們需要記住兩個值, 1. 已選出多少牌:n 2. 還剩下多少牌:這個可以用 10 - i 得到 for ( size_t i=0; i<10; ++i ) { if ( rand() % (10-i) < (3-n) ) { ++ n ; cout << i ; } } 空間複雜度 O(1),時間複雜度 O(總牌數)。 當總牌數遠大於要抽出牌數的話,這個方法就不適用。 -- To iterate is human, to recurse, divine. 遞迴只應天上有, 凡人該當用迴圈.   L. Peter Deutsch -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.45.107.213

02/13 08:31, , 1F
為甚麼總牌數遠大於要抽的牌數就不適用?
02/13 08:31, 1F

02/13 10:41, , 2F
m/n n=總 m=抽 當n>m很多時抽出來機率就小 => O(n)
02/13 10:41, 2F

02/13 11:05, , 3F
學到好方法^^..,收藏起來。
02/13 11:05, 3F

02/13 12:05, , 4F
回二樓 但是有什麼演算法 可以不用看過全部的牌
02/13 12:05, 4F

02/13 12:06, , 5F
卻可以保證取出來的牌是均勻分配?
02/13 12:06, 5F

02/13 12:48, , 6F
Sorry 我搞錯了.. 當我沒問
02/13 12:48, 6F

02/15 14:01, , 7F
這段程式似乎有 BUG ,沒人看出來嗎?
02/15 14:01, 7F

02/16 19:01, , 8F
原來是我看錯了...
02/16 19:01, 8F
文章代碼(AID): #1BTUu3xG (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1BTUu3xG (C_and_CPP)