微信紅包的概率測試程式

lt發表於2017-02-03

演算法: 比如100元發給10個人,每個紅包至少一元,那麼第1個最多得100-9=91,這樣才夠後面的人分. 第2個最多得剩下的減8,以此類推直到倒數第2人。最後1人直接得剩下的。 但是這樣一來,隨機性就變了。從實驗結果看,第一個就沒有得1的,後面很多個都得1。

#include <cstdio>
#include <ctime>
#include <cstdlib>
void hb()
{
    int total=100;
    int minv=1;
    int count=5;
    int sum=0;

    for(int c=1; c<=count; c++)
    {
        int x=rand()%(total-minv*(count-c))+minv;
        if(c==count )x=total;
        printf("%d ",x);
        total-=x;
        sum+=x;
    }
    printf(" =%d\n",sum);
}
int main()
{
    srand(time(NULL));
    for(int i=0; i<30; i++)
        hb();
}

測試結果

--------------------100發給5人
34 62 1 2 1  =100
38 19 18 4 21  =100
16 36 44 1 3  =100
93 4 1 1 1  =100
53 17 26 2 2  =100
22 56 9 1 12  =100
6 16 71 3 4  =100
43 44 4 3 6  =100
14 62 3 16 5  =100
30 29 2 7 32  =100
52 5 10 21 12  =100
75 10 6 8 1  =100
90 4 1 2 3  =100
74 14 4 2 6  =100
59 3 19 1 18  =100
91 4 2 2 1  =100
64 27 2 4 3  =100
25 64 3 1 7  =100
2 83 3 6 6  =100
88 3 7 1 1  =100
14 66 7 2 11  =100
3 15 12 47 23  =100
43 49 5 2 1  =100
61 2 7 4 26  =100
16 79 3 1 1  =100
61 13 7 2 17  =100
41 52 4 1 2  =100
78 16 2 2 2  =100
34 34 26 1 5  =100
26 50 19 3 2  =100
-----------------------------100發給10人
57 2 12 15 1 9 1 1 1 1  =100
10 51 21 2 9 3 1 1 1 1  =100
27 2 3 42 11 1 2 1 7 4  =100
74 5 10 4 2 1 1 1 1 1  =100
57 26 1 6 3 2 2 1 1 1  =100
71 2 3 12 7 1 1 1 1 1  =100
82 2 4 3 1 1 4 1 1 1  =100
51 17 9 1 11 7 1 1 1 1  =100
85 3 2 3 1 1 2 1 1 1  =100
42 35 6 8 2 3 1 1 1 1  =100
39 14 20 14 6 3 1 1 1 1  =100
78 3 11 2 1 1 1 1 1 1  =100
24 43 21 4 2 1 2 1 1 1  =100
79 13 1 1 1 1 1 1 1 1  =100
1 70 7 11 1 3 1 3 2 1  =100
87 5 1 1 1 1 1 1 1 1  =100
70 20 3 1 1 1 1 1 1 1  =100
8 34 45 3 1 4 2 1 1 1  =100
35 51 2 6 1 1 1 1 1 1  =100
26 57 2 3 3 3 3 1 1 1  =100
78 10 1 1 4 2 1 1 1 1  =100
81 5 3 3 2 2 1 1 1 1  =100
81 5 6 1 2 1 1 1 1 1  =100
26 60 4 1 3 1 1 1 1 2  =100
78 10 1 4 1 1 2 1 1 1  =100
88 1 3 2 1 1 1 1 1 1  =100
84 7 2 1 1 1 1 1 1 1  =100
50 10 20 5 5 6 1 1 1 1  =100
77 10 1 6 1 1 1 1 1 1  =100
42 29 3 18 3 1 1 1 1 1  =100
------------------------------1000發給10人
299 665 4 1 21 4 3 1 1 1  =1000
887 88 18 1 1 1 1 1 1 1  =1000
719 161 112 2 1 1 1 1 1 1  =1000
276 268 216 46 156 23 9 3 1 2  =1000
620 160 169 42 4 1 1 1 1 1  =1000
700 230 52 3 9 1 1 2 1 1  =1000
541 313 120 4 16 1 1 2 1 1  =1000
695 183 18 62 23 3 2 4 4 6  =1000
307 417 21 81 155 13 3 1 1 1  =1000
894 14 63 8 2 4 7 6 1 1  =1000
428 543 5 15 2 3 1 1 1 1  =1000
83 61 391 52 165 202 34 6 1 5  =1000
492 205 75 180 17 8 4 7 5 7  =1000
971 8 10 5 1 1 1 1 1 1  =1000
381 140 167 246 30 18 7 8 2 1  =1000
403 553 3 18 15 4 1 1 1 1  =1000
456 98 105 188 103 32 2 8 4 4  =1000
990 2 1 1 1 1 1 1 1 1  =1000
77 70 86 521 133 42 20 49 1 1  =1000
585 158 122 35 90 1 6 1 1 1  =1000
645 327 20 2 1 1 1 1 1 1  =1000
711 198 52 24 4 3 3 3 1 1  =1000
432 517 36 6 3 2 1 1 1 1  =1000
181 94 185 152 346 15 17 3 2 5  =1000
277 60 483 56 43 41 18 14 2 6  =1000
669 216 64 33 4 5 1 1 2 5  =1000
346 378 125 111 6 13 3 14 3 1  =1000
171 523 88 86 89 27 6 2 2 6  =1000
554 63 344 20 2 13 1 1 1 1  =1000
405 526 10 38 13 2 1 2 1 2  =1000

我又想到1種思路,最初就確定最終發包的數量,生成與人數相同的隨機數,然後將隨機數排序,按順序發給不同金額,但第幾名得多少不好確定。
https://www.zhihu.com/question/22625187 提到,每個包的上限是剩餘均值的2倍,根據這個思路,把分配的語句改為int x=rand()%(total*2/(count-c+1))+minv;,這樣方差小多了。

------------------------------100發給10人
10 2 4 10 23 9 5 4 31 2  =100
6 16 3 9 19 8 17 7 12 3  =100
19 4 18 16 7 5 1 17 5 8  =100
4 6 10 20 12 4 19 13 2 10  =100
15 14 11 12 15 12 7 8 3 3  =100
20 13 12 3 13 3 18 9 4 5  =100
6 4 20 1 1 25 21 2 19 1  =100
6 19 6 17 13 4 2 10 16 7  =100
15 11 16 1 3 3 13 25 8 5  =100
1 19 15 17 11 3 11 7 7 9  =100
1 5 8 16 11 5 16 10 22 6  =100
10 15 10 9 12 15 7 8 4 10  =100
5 18 2 11 16 8 18 8 9 5  =100
5 4 3 5 19 19 10 15 9 11  =100
2 2 3 11 27 21 8 16 6 4  =100
18 2 5 4 7 10 27 3 7 17  =100
18 18 8 10 11 13 6 1 4 11  =100
10 17 5 7 11 12 6 6 17 9  =100
13 7 15 14 9 12 11 7 4 8  =100
4 13 18 11 18 7 10 12 4 3  =100
12 5 17 14 1 6 20 10 5 10  =100
14 12 3 1 16 10 4 12 15 13  =100
5 5 1 11 18 15 11 17 4 13  =100
18 5 17 4 12 14 1 11 7 11  =100
8 1 12 8 8 6 11 8 27 11  =100
10 2 4 19 6 19 2 14 4 20  =100
17 8 4 4 7 21 16 2 11 10  =100
11 15 11 8 12 9 10 1 2 21  =100
8 6 2 5 7 7 8 22 10 25  =100
17 13 9 5 18 11 4 11 8 4  =100
------------------------------------------1000發給10人
200 12 70 148 166 44 157 20 80 103  =1000
70 94 5 196 185 58 78 134 99 81  =1000
187 70 95 30 104 76 27 242 151 18  =1000
110 5 44 164 152 58 222 152 13 80  =1000
190 55 182 26 169 151 52 70 27 78  =1000
74 87 66 17 108 78 26 25 55 464  =1000
5 75 16 144 240 202 129 8 137 44  =1000
32 24 208 71 121 213 57 51 132 91  =1000
144 26 106 94 196 159 84 48 85 58  =1000
73 151 8 196 32 125 131 29 191 64  =1000
139 79 99 94 81 76 113 156 105 58  =1000
88 131 148 136 6 68 191 5 114 113  =1000
142 174 44 84 184 85 138 80 52 17  =1000
18 173 96 51 48 50 250 103 123 88  =1000
79 62 66 160 108 157 130 40 80 118  =1000
30 214 111 38 108 35 190 176 10 88  =1000
14 187 38 203 59 163 24 171 72 69  =1000
78 62 94 33 201 169 161 65 73 64  =1000
121 17 80 87 165 92 158 29 7 244  =1000
198 92 111 40 137 3 132 83 171 33  =1000
193 92 160 43 105 155 33 37 77 105  =1000
12 74 173 130 101 59 94 166 8 183  =1000
164 108 71 72 36 88 230 10 101 120  =1000
33 68 170 91 61 59 20 107 360 31  =1000
140 166 23 186 2 41 159 101 16 166  =1000
6 101 187 137 10 78 30 124 204 123  =1000
191 42 106 91 120 130 90 38 96 96  =1000
66 5 8 234 208 33 193 160 78 15  =1000
192 86 74 17 183 1 12 216 115 104  =1000
35 160 44 84 79 33 231 125 101 108  =1000

看最佳手氣出現的位置。

#include <cstdio>
#include <ctime>
#include <cstdlib>
static int best_count[11]={0};
void hb()
{
    int total=1000;
    int minv=1;
    int count=10;
    int sum=0;
    int best=0,bestpos=0;
    for(int c=1; c<=count; c++)
    {
        int x=rand()%(total*2/(count-c+1))+minv;
        if(c==count )x=total;
        if(x>best)
        {
            best=x;
            bestpos=c;
        }

        //printf("%d ",x);
        total-=x;
        sum+=x;
    }
    //printf(" sum=%d bestpos=%d\n",sum,bestpos);
    best_count[bestpos]++;
}

int main()
{
    srand(time(NULL));
    for(int i=0; i<10000; i++)
        hb();
    for(int c=0; c<=10; c++)
        printf("best_count[%d]=%d\n",c,best_count[c]);
}

結果,2~7輪抽中的概率明顯低

best_count[0]=0
best_count[1]=1074
best_count[2]=946
best_count[3]=929
best_count[4]=835
best_count[5]=910
best_count[6]=915
best_count[7]=971
best_count[8]=1077
best_count[9]=1169
best_count[10]=1174

D:\>a
best_count[0]=0
best_count[1]=1003
best_count[2]=958
best_count[3]=918
best_count[4]=915
best_count[5]=887
best_count[6]=907
best_count[7]=998
best_count[8]=1053
best_count[9]=1197
best_count[10]=1164

D:\>a
best_count[0]=0
best_count[1]=1095
best_count[2]=963
best_count[3]=945
best_count[4]=855
best_count[5]=892
best_count[6]=909
best_count[7]=965
best_count[8]=1035
best_count[9]=1148
best_count[10]=1193

這個演算法還有一個明顯的問題,第一輪最多抽總數*0.2的金額,後面的可能抽到更大的。

---測試100次
best_value[0]=0
best_value[1]=199
best_value[2]=195
best_value[3]=206
best_value[4]=224
best_value[5]=248
best_value[6]=235
best_value[7]=242
best_value[8]=306
best_value[9]=400
best_value[10]=262
---測試100次
best_value[0]=0
best_value[1]=200
best_value[2]=218
best_value[3]=218
best_value[4]=235
best_value[5]=238
best_value[6]=258
best_value[7]=304
best_value[8]=259
best_value[9]=307
best_value[10]=415

相關文章