1
starvedcat 2017-04-26 10:49:23 +08:00 13
取 29 个(0, 100)的坐标
|
2
hinate 2017-04-26 10:53:35 +08:00
|
3
xialdj 2017-04-26 10:55:12 +08:00 via iPhone 5
随便生成 30 个随机数 按照总和与 100 的比例 所有数字等比例缩放
|
5
crist OP 其实我是这样想的:平均分成 30 份每份 10 元,然后再从这 10 元里面随机抽取几元钱,然后再随机分配给每一份,就 OK 啦
|
6
coderluan 2017-04-26 11:12:40 +08:00
没特殊要求的话,基本怎么算都能实现吧。
|
8
Vizogood 2017-04-26 11:16:04 +08:00 via iPhone
楼主是不是要写一个红包算法 (滑稽
|
10
crist OP @crist 说错了,好像 100 分成 30 份并不是每份 10 哈应该是 3.33333333333333333333333333333 元
|
11
tankb52 2017-04-26 11:26:48 +08:00 1
建 30 个人的群,发 100 块钱红包啊
|
12
ioriwong 2017-04-26 11:30:33 +08:00 via Android
用一楼 挡板法 就行了
|
14
johnny23 2017-04-26 11:38:57 +08:00 via iPhone
random100 次 每次都取模 3 结果为 0 给第一份红包加一 为 1 加二个红包 为 2 加第三个红包 不知道这样如何?
|
15
zhangbohun 2017-04-26 11:39:15 +08:00 via Android 1
随机生成三十个数,然后每个除以总和乘以 100 生成前九十九个,最后一个 100 减前面的九十九个。
|
16
johnny23 2017-04-26 11:39:51 +08:00 via iPhone
看错题目了 楼主可以无视我 哭...
|
17
zhaojjxvi 2017-04-26 11:39:53 +08:00 via iPhone
@starvedcat 说实话没太懂怎么保证各项和等于 100
|
18
crist OP 29 个(0, 100)的坐标怎么取,用什么语言?能否 30 份每一份都是随机数量的?
|
19
johnny23 2017-04-26 11:41:30 +08:00 via iPhone
改良哈 random ( 30 ) 70 次
|
21
johnny23 2017-04-26 11:45:56 +08:00 via iPhone
重新来 先从 100 元扣出 30 分分别放在 30 个红包里面一个红包一分钱 然后做 9970 次 random(30 的运算) 随机结果是多少就给对应的红包加一分钱 比如 25 就给第 25 个红包加一分钱 直到 9970 次结束
|
22
SingeeKing 2017-04-26 12:35:27 +08:00
找来 29 个人建个群,发 100 元分 30 个包,大家领完记录就好了
|
23
RqPS6rhmP3Nyn3Tm 2017-04-26 12:43:37 +08:00 via iPhone
离散数学基础啊哥
|
24
crist OP @johnny23 根据你的描述,应该随机 100 次就已经结束了,为什么还要随机 9970 次呢?除非你是想把 100 块分成 9970 份啊,这样也是 OK 的,不过太耗费资源了,分成 500 个小份再随机加到 30 个红包里面就可以了。点子不错,谢谢你~~
|
25
libook 2017-04-26 14:05:46 +08:00
循环随机二分?
循环 29 次,每次把剩下的钱随机分成两份,一份分出去,另一份进入下一次循环。 不知道在概率学上和 1 楼的区别,有大牛来讲一下吗? |
26
blankme 2017-04-26 14:09:36 +08:00 1
@libook 1 楼是最标准的做法,每份的期望值都是 100/30.
你的做法得到的每份红包期望值都不一样,比如第一份是 50. |
27
acros 2017-04-26 14:10:29 +08:00
困扰的主要是红包带来的潜在限制条件吧··· 分的平均了没意思,大小太极端不行。
所以这个做好后还需要测试下,最好建个群分真钱测试,这样可以如实调研用户心理。 --- 楼主建好这个群后请务必加我。我有时间帮你测试! |
28
jiangzhuo 2017-04-26 14:23:58 +08:00
楼上说发红包的方法,如果有人不领红包怎么能保证我最后得到 30 个数字。
|
29
crist OP $total = 100;
$pr = 1000; // 分成小份数 $bit = $total / $pr; $array = []; for ($i=0; $i < $pr; $i++) { $array[rand(0,29)] += $bit; } echo "<pre>";print_r($array); echo "total = " . array_sum($array); |
30
vicalloy 2017-04-26 14:44:28 +08:00
最主要的问题是每次分完后,剩下的前足够余下的人分。
简单的写了一下,可能会有 bug https://gist.github.com/vicalloy/7225cf8749e427882e0e70138353739a |
33
lygmqkl 2017-04-26 15:10:13 +08:00
我贡献一个思路,首先要看细分的程度,如果每个人都要有,而且粒度到 1 元,那么就
第一轮先每人给 1 块,剩下 70 元,再进入第二轮 第二轮拿出 30 元,每人 mt_rand(0,1), 如果 0 则不分配,如果 1 则分配 1 元,余下未分配的放回奖池 第三,第四,第五轮, repeat 第二轮 理论上 第三轮结束,应该已经分配出去 90 元, 所以还是很快的。 如果是要到 0.01 ,那么就以 10000 为基数,第一轮每人 1 , 剩下每轮 0-3000 也可以 0-1000 ,多跑几个循环即可。 理论上结果应该和一楼隔板法很接近,其实我是赞同一楼的,但是这种以轮为单位的方法感觉也 ok ,并没有多跑几次,而且看起来更均匀和公平。 |
35
viator42 2017-04-26 15:14:00 +08:00
取一个 0 到 100 的随机数,这个数作为第一份,然后 100 减去这个数,剩下的钱再随机,29 次之后剩下的钱作为第三十份
|
36
ifishman 2017-04-26 15:18:50 +08:00 via Android
@blankme 既然楼主需要的是红包算法,那就不能采用相同期望值的算法,红包就应该是第一个人抢的时候最容易抢最多的,第二个次之……
|
37
Domains 2017-04-26 15:20:25 +08:00
这不就是红包?
理论要看实践 到我这都 36 楼了,要不 LZ 开个群, 100 发个 30 人红包,每次统计好,发一百次 |
38
Domains 2017-04-26 15:23:35 +08:00
@ifishman 你要是真抢过红包,你就知道错得过分,抢红包出现在中后段出现的金额普遍较高。另,这真有实践题,有人就专门测试过的,金额高于平均值的普遍出现于中段后
|
39
Monad 2017-04-26 15:23:47 +08:00
直接插板法就好了 高中数学
|
40
srlp 2017-04-26 15:27:40 +08:00
|
41
Vizogood 2017-04-26 15:28:58 +08:00 via iPhone
|
42
crist OP 29 楼我那个方法有点缺陷哈:就是结果起伏变化不是很大, 100 块钱 30 份的每一份都很少有低于 2.0 或者高于 4.0 的
|
44
wbt 2017-04-26 16:21:44 +08:00
随机生成 30 个( 0-1 之间的)数字,然后求和计算每个数字的百分比,最后乘以 100 。
|
45
rogerchen 2017-04-26 16:29:24 +08:00 via Android
#1 隔板法
#14 正则化 两个都是好方法,正则化可以完全控制分布 |
46
slixurd 2017-04-26 16:37:52 +08:00
"首先,我来讨论一下为什么要采用截尾正态分布。首先介绍一种更加直接的方法(我有一些朋友也这样猜测):如果我有 50 元,要发给 25 人。那么我用连续均匀分布随机产生 24 个位于 0 到 50 之间的数字。这 24 个数字将整个 0-50 的区间划分为 25 份,分别分给这 25 个人。但事实并不是这样的。学过序列统计的人应该知道,由于这 24 个点是连续均匀分布产生的,因此他们的序列统计量也是连续均匀分布产生的,因此他们之间的间隔的分布是指数分布的。具体证明从略,可参照 John Rice 2007 。
作者: Mr.L 链接: https://www.zhihu.com/question/22625187/answer/85431684 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。" |
48
qxd123 2017-04-26 16:53:30 +08:00
关于这个问题,如果单纯为了每个人获得的金额都相差不大的话,用一楼的确实就够用了,但如果要想跟微信红包差不多的结果,用正态分布的算法来更为合理,楼上也都给出了些方法,在保证大部分人的金额处于平均数附近,但是又有极少人的金额是相对大一点或者小一点,另外之前在网上看到过类似这种的,可以参考看看 https://segmentfault.com/q/1010000006002081
|
49
geelaw 2017-04-26 16:57:27 +08:00
你这个问题根本不是 well-asked ,都不知道你想要什么分布,怎么随机?
|
50
di94sh 2017-04-26 17:28:19 +08:00 via Android
就一楼的方法, 10000 里面生成 29 个不想等的随机数,大小排序,从零开始判断区间。/100 可以精确到分。
|
51
fl2d 2017-04-26 17:44:57 +08:00
你要的是啥分布的随机,这很重要
|
52
wangleineo 2017-04-26 17:53:57 +08:00
实践出真知,楼主建个群发红包,看看微信红包到底什么分布。
|
53
zjp 2017-04-26 19:01:09 +08:00 via Android
是我想的太简单吗😂 #15 的方法不就可以了吗
|
54
yellowV2ex 2017-04-26 20:14:57 +08:00
随机 100 个数记下来,再计算他们的和,然后每一份的钱就是
每一个随机数 ------------------- x 100.00 所有随机数总和 |
55
qqjt 2017-04-26 20:35:45 +08:00
钱应该最小是 0.01 , 0-100 间有 999 个取值,问题变成了 [1-999]里面随机取 30 个整数。
|
57
Actrace 2017-04-26 21:14:39 +08:00 1
既然入坑了,我就贴一下代码把。。
``````````` <?php $total = 10000;//总额,按分 $max = 500;//最大可分额度 $min = 100;//最小可分额度 $times = 30;//分几个人 for($i=1;$i<=$times;$i++){ $exp = ($total-($times-$i))>$max?$max:($total-($times-$i)); $now = rand($min, $exp); $total = $total - $now; $f1 = $now/100; $f2 = $total/100; echo "//第{$i}个人:{$f1}元,剩余{$f2}元。\n"; } echo "//第 30 个人:{$f2}元。\n"; ?> ```````````` //第 1 个人:3.69 元,剩余 96.31 元。 //第 2 个人:2.82 元,剩余 93.49 元。 //第 3 个人:4.79 元,剩余 88.7 元。 //第 4 个人:3.57 元,剩余 85.13 元。 //第 5 个人:4.39 元,剩余 80.74 元。 //第 6 个人:2.45 元,剩余 78.29 元。 //第 7 个人:2.1 元,剩余 76.19 元。 //第 8 个人:4.89 元,剩余 71.3 元。 //第 9 个人:4.93 元,剩余 66.37 元。 //第 10 个人:4.19 元,剩余 62.18 元。 //第 11 个人:2.2 元,剩余 59.98 元。 //第 12 个人:4.52 元,剩余 55.46 元。 //第 13 个人:4.67 元,剩余 50.79 元。 //第 14 个人:3.92 元,剩余 46.87 元。 //第 15 个人:3.44 元,剩余 43.43 元。 //第 16 个人:1.32 元,剩余 42.11 元。 //第 17 个人:1 元,剩余 41.11 元。 //第 18 个人:3.52 元,剩余 37.59 元。 //第 19 个人:2.21 元,剩余 35.38 元。 //第 20 个人:4.19 元,剩余 31.19 元。 //第 21 个人:1.29 元,剩余 29.9 元。 //第 22 个人:2.87 元,剩余 27.03 元。 //第 23 个人:4.88 元,剩余 22.15 元。 //第 24 个人:3.98 元,剩余 18.17 元。 //第 25 个人:2.93 元,剩余 15.24 元。 //第 26 个人:3.83 元,剩余 11.41 元。 //第 27 个人:3.82 元,剩余 7.59 元。 //第 28 个人:1.57 元,剩余 6.02 元。 //第 29 个人:1.26 元,剩余 4.76 元。 //第 30 个人:2.2 元,剩余 2.56 元。 //第 30 个人:2.56 元。 |
58
Actrace 2017-04-26 21:18:17 +08:00
过大的粒度可能会让结果偏离更大,比如一个人拿了 99 块钱。。
过小的粒度同样如此,最后一个人拿了 99 块钱。。。 |
59
mingyun 2017-04-26 23:03:43 +08:00
可以参考微信红包算法
|
60
zhihaofans 2017-04-26 23:38:12 +08:00
|
62
imn1 2017-04-27 00:14:55 +08:00
|
64
Actrace 2017-04-27 00:40:34 +08:00
@imn1 你提到的问题好解决,如果你想要让某个人获得最高值的概率是随机的,可以把红包提前分配好,然后再将分配好的红包配额随机分发给其他人。
理论上来说,算法本身是合理的,因为随机数函数本身就是随机的。按照微信红包的那种设定,即使第一个人领取了更多的配额,这也是随机的,不存在公平性问题讨论,因为这里的目标是“随机”,实际上第一个领红包的人也是随机的。 设定 min 和 max 也只是为了让落差有一个可控的程度,也就是说楼主想要“公平”的话,这个是附加福利(可选项)。 |
65
imn1 2017-04-27 00:46:15 +08:00
@libook
依题目,只要符合一次整体随机就可以了,就是数额和顺序,所以递减逐次随机取数额及随机顺序应该满足 不过我个人不太喜欢,又说不出什么道理 个人倾向#15 的权重方法,这种方法是不理会总额的完全随机,再换算成总额 100 的占比 #1 插板法理论上也是完全随机,但这种方法有个弊端,就是不能在相同位置插两块,所以程序是要限制的 而#15 则没有这个问题 |
66
imn1 2017-04-27 00:52:19 +08:00
|
67
zhangsen1992 2017-04-27 09:46:28 +08:00
l = [random.randint(0,100) for i in range(30)]
map(lambda x:100*x/float(sum(l)),l) |
68
imn1 2017-04-28 18:02:45 +08:00
再补充一下:
这个不同抽样方法之间的区别就是,每次抽取的样本是否返回样本库,是,则为排列,否,则为组合 #1 每次取值均不能与前面相同,就是样本不返回样本库 #15 可以多次相同值,所以是样本返回样本库,而且理论上样本库无限大,只要计算机能处理则可 而每次扣除取出金额,递减再随机,也是不返回样本库,而且样本库的减少比#1 插板法更甚 至于平均再腾挪,属于分段抽样法,样本库远小于前面三种 其实哪种方法都能实现目标(没有离题),看需求选择啰 |