1. 程式人生 > >生成不重複隨機數的方法 --抽獎問題等

生成不重複隨機數的方法 --抽獎問題等

問題描述:
給定一個n,一個m
要求在1 ~ n這n個數字中,生成m個不重複的隨機數。

思路:
生成隨機數大家都知道,C++中也提供了相關的函式——rand()。
但是問題中要求生成的是無重複的隨機數,這裡就需要對生成的隨機數進行去重操作了。

首選最直觀的思路是可以使用set,利用set的無重複的性質對數字進行過濾。
演算法如下:

    while (s.size() < m) {
        s.insert(rand() % n + 1);       //取隨機數取模,由於從1開始,故後面+1
    }

那麼,出了set之外,是否還有其他思路呢?

舉個例子,對於1,2,3,4,5這五個數字來說,取兩個隨機數,那麼我們可以模擬整個取數的過程。
首先對於數字1,取1 的概率為2/5.
對於數字2,則要分為兩種情況:
1.數字1已經取到,那麼在這個前提下,剩下4個數字取一個即可,每個數字被取到的概率是1/4
2.數字1未被取到,那麼這個問題就縮小為在2~4這4個數字中,取2個數字,此時的2被取到的概率為2/4。

以此類推,我們可以對整個取數字的過程進行模擬。

    for (int i = 1; i <= n; ++i) {
        //例如,n = 5, m = 2時
        //在剛開始,第一次抽的時候,數字1被抽中的概率為2/5
        if (rand() % (n-i+1) < num) {           //抽中的情況
            cout << i << " ";       //此時i被抽中,輸出i
            --num;
        }
        if (!num)
            break;              //取夠了的情況
}

那麼,還有沒有其他的思路呢?答案是有的。

既然要求隨機,那麼對於亂序的1~n的數字,直接輸出前m項,即為所求。
於是我們可以將陣列存入陣列中對其亂序,輸出前m項便可得到結果。

//Algorithm 3
//將陣列亂序後輸出前m項即可

    int *arr = new int[n];
    for (int i = 0; i < n; ++i)
        arr[i] = i + 1;
    for (int i = 0; i < m; ++i) {
        int temp = rand() % n;
        swap(arr[i], arr[temp]);
    }

整體程式碼如下。

// 隨機數生成.cpp : 定義控制檯應用程式的入口點。
//
//從1~n這個數字中生成m個不重複的數字
#include "stdafx.h"
#include <iostream>
#include <set>
#include <algorithm>
#include <cstdlib>
using namespace std;
int main()
{
    //Algorithm 1
    //模擬抽取的過程,結果為有序
    int n, m;
    cin >> n >> m;
    int num = m;
    for (int i = 1; i <= n; ++i) {
        //例如,n = 5, m = 2時
        //在剛開始,第一次抽的時候,數字1被抽中的概率為2/5
        if (rand() % (n-i+1) < num) {           //抽中的情況
            cout << i << " ";       //此時i被抽中,輸出i
            --num;
        }
        if (!num)
            break;              //取夠了的情況
    }
    cout << endl;

    //Algorithm 2 
    //使用set過濾
    set <int> s;
    while (s.size() < m) {
        s.insert(rand() % n + 1);       //取隨機數取模,由於從1開始,故後面+1
    }
    for (auto iter = s.begin(); iter != s.end(); ++iter)
        cout << *iter << " ";
    cout << endl;

    //Algorithm 3 
    //將陣列亂序後輸出前m項即可

    int *arr = new int[n];
    for (int i = 0; i < n; ++i)
        arr[i] = i + 1;
    for (int i = 0; i < m; ++i) {
        int temp = rand() % n;
        swap(arr[i], arr[temp]);
    }
    sort(arr, arr + m);
    for (int i = 0; i < m; ++i)
        cout << arr[i] << " ";
    cout << endl;
    return 0;
}

執行結果如下。

這裡寫圖片描述