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

看板C_and_CPP作者 (非天夜翔)時間15年前 (2010/02/13 03:03), 編輯推噓1(105)
留言6則, 3人參與, 最新討論串3/3 (看更多)
※ 引述《yoco315 (眠月)》之銘言: : 假設要從十張裡面抽出三張 : 我們就知道每張牌被抽出來的機率是 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 還需要多少牌:k : 2. 還剩下多少牌:這個可以用 10 - i 得到 : for ( size_t i=0; i<10; ++i ) { : if ( rand() % (10-i) < (3-n) ) { if ( rand() % (10-i) < k ) { // replace : ++ n ; -- k ; // replace : cout << i ; if( k == 0 ) break; // add : } : } : 空間複雜度 O(1),時間複雜度 O(總牌數)。 O(總需求數) <<<< 我講錯了。 : 當總牌數遠大於要抽出牌數的話,這個方法就不適用。 -- 渴望飛翔在自由中, 期望逃離這拘束的現實, 一切都讓他隨著而去, 獨自躲在黑暗空氣中, 舔舐被狠狠撕裂的傷口。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 211.74.9.2

02/13 11:07, , 1F
可以的話把k寫成常數,然後把所有的10改成k@@
02/13 11:07, 1F

02/13 11:10, , 2F
n不就是紀錄已經抽幾張了@@,那條件直接寫k==n應該比較好
02/13 11:10, 2F
我的方式是用 k 而沒有 n

02/13 11:11, , 3F
時間複雜度一樣是O(總牌數)
02/13 11:11, 3F
多謝指教,原來是我的認知有錯。 m(_@_)m

02/13 11:18, , 4F
至少程式學聰明了些@@,不過還是可能要跑到總牌數。
02/13 11:18, 4F
※ 編輯: csihcs 來自: 211.74.9.2 (02/13 11:33)

02/13 12:50, , 5F
這問題有個有趣的延伸 如果總牌數是未知的該如何取?
02/13 12:50, 5F
文章代碼(AID): #1BTXPu8w (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1BTXPu8w (C_and_CPP)