微信抢红包神器红包0.69元表示么意思

微信红包的随机算法是怎样实现的?
RT。我考虑了一个简单的算法:比如100元,由10个人分,那么平均一个人是10元钱。然后付款后,系统开始分份儿。第一份:系统由0~10元之间随机一个数,作为这一份的钱数,设x1。第二份:剩下的钱(100-x1),系统由0~(100-x1)/(10-1)随机一个数,作为这份的钱数,设x2.。。。第n份:剩下的钱(100-x1-x2-...-xn),系统由0~(100-x1-x2-...-xn-1)/(10-n)随机一个数,作为这个份的钱数,设为xn当用户进来拿红包的时候,系统由0~9之间随机一个数,随机到几,就取第几份红包,然后将这个数存到list里。当之后的用户抽到相同的随机数时,则将这个数+1,如遇相同再+1,直至list满,红包发完。------------------------------------------------我这么实现可以么??或者大家有更好的办法????
按投票排序
楼上大多数人都是在做出自己的猜测,这也是在不知道内部随机算法的时候的唯一选择,但是大多数人没有给出自己亲自的调查结果。这里给出一份100样本的调查抽样样本数据,并提出自己的猜测。1.
钱包钱数满足截尾正态随机数分布。大致为在截尾正态分布中取随机数,并用其求和数除以总价值,获得修正因子,再用修正因子乘上所有的随机数,得到红包价值。
这种分布意味着:低于平均值的红包多,但是离平均值不远;高于平均值的红包少,但是远大于平均值的红包偏多。图1. 钱包价值与其频率分布直方图及其正态拟合
但看分布直方图并不能推出它符合正态分布,但是考虑到程序的简洁性和随机数的合理性,这是最合乎情理的一种猜测。2.
越是后面的钱包,价值普遍更高图2. 钱包序列数与其价值关系曲线
从图2中的线性拟合红线可以看到,钱包价值的总体变化趋势是在慢慢增大,其变化范围大约是一个绿色虚线上下界划出的“通道”。(曲线可以被围在这么一个正合乎常规的“通道”中,也从侧面反映了规律1的合理性,说明了并不是均匀分布的随机数)
从另一个平均数的图中也可以看出这一规律。图3. 平均数随序列数的变化曲线在样本中,1000价值的钱包被分成100份,均值为10。然而在图3中我们可以看到在最后一个钱包之前,平均数一直低于10,这就说明了一开始的钱包价值偏低,一直被后期的钱包价值拉着往上走,后期的钱包价值更高。3.
当然平均数的图还可以透露出另一个规律,那就是最后的那一个人往往容易走运抽得比较多。因为最后那一个人是钱包剩下多少就拿多少的,而之前所有人的平均数都低于10,所以至少保证了最后一个人会高于平均值。在本样本中,98号钱包抽到35,而最后一份钱包抽到46。综上,根据样本猜测:1.
抽到的钱大多数时候跟别人一样少,但一旦一多,就容易多很多。2.
越是抽后面的钱包,钱越容易多。3.
最后一个人往往容易撞大运。
其实这些一点用的没有,就是自己闲了无聊开一开脑洞,大家别认真,玩红包开心就好哈哈,土豆祝大家新年快乐啦~
——Potato
据观察,红包分钱满足以下几点:不会有人拿不到钱不会提前分完钱的波动范围很大 的答案我完全同意。红包在一开始创建的时候,分配方案就订好了。抢红包的时候,不过是挨个pop up而已。针对他说的算法二写个 python 代码。def weixin_divide_hongbao(money, n):
divide_table = [random.randint(1, 10000) for x in xrange(0, n)]
sum_ = sum(divide_table)
return [x*money/sum_ for x in divide_table]
不过上述算法还有两个小问题:浮点数精度问题边界值的处理不过,都是很容易解决的小问题,你们看的是算法思想,对吧。
我觉得这个问题的合理解有两个目标:1. 不要出现人为的阈值,比如预留值、最大和最少量、切割比例等拍脑袋的数据。2.尽量贴近过年的喜庆气氛,不要出现太多或者太少的情况。如果有什么其它考虑,方便实现成代码也算一个。所以我的思路其实用一句话就可以概括:生成n(n是总人数)个(0,1]之间的随机数,然后将其求和被Q(Q是总钱数)除得到一个比例C,用C乘以所有数,这样就得到了最终结果。这个算法很多人都会想到,但是被大家抛弃的原因应该在于随机性太大。那么我想到的修正方案:生成随机数时不要采用平均分布的随机数,而用正态分布的随机数。可是系统提供的随机数算法基本都是基于平均分布的,那现在提供一个平均分布映射到正态分布的算法就可以了。其实这个算法很常见,假设生成的平均分布数是x,正态分布所求值是y,正太分布表达式是f(y),那么f(y)求积分记为F(y),根据这样一个式子F(y) = x,求出F(y)的反函数就是所需要的映射函数。这个看起来很复杂,其实求出一个式子后代码写起来很简单。原谅我的数学表达基本已经都忘了,如果有写错,欢迎指正。所以这个算法只需要两个function就可以实现,下面是个伪代码 :double generateRandomNumber(){
//generate random number based on normal distribution}void process(double totalMoney, int personNum){
double[personNum]
for (int i=0; i & personN i++){
results[i] = generateRandomNumber();
double ratio = totoalMoney/sum(results);
for (int i=0; i & personN i++){
results[i] = result[i] *
}}PS:这个算法的生产随机数其实是可配置的,取决于开发者希望最终趋近于什么样的分布,只要找到其和平均分布的映射关系,就可以使用什么样的生成算法。PPS:这个分布算法如果能让用户配置会更好玩,比如配置成1个人领50%,3个人领30%,剩下的人分20%,还会有抽大奖的感觉,哈哈哈~
我们昨天几个人讨论了一晚上。题主算法的问题是,有可能有一个人一下子把所有钱拿走了,而其他人都没有得到钱。然后按照我对现在发出去和别人发的红包的观察,认为算法应该满足以下几个条件:1、不能一个人一下子把钱拿走,也就是有预留额;2、一个人拿到极小数(比如0.01元)的概率远大于拿到极大数(99%的总额)的概率;3、多数人都是在平均数附近浮动的。为了满足这几个条件,我提出一个算法假设:1、使用偏正态分布产生各个红包;2、有人为的红包上限设置,也即最大的红包不超过平均值的k倍,k的数值与红包个数n有关,同时也受到红包平均数money/n这个绝对值的制约;采用这个算法的话,获得的红包同现在的情况比较符合。但是对于算法的第二点,我还无法做出更好的猜测,因为本人和朋友发红包的数量不多,无法做出基于大样本的猜测。
在看数据之前,我先说说自己的想法:1. 把钱看成连续的,分完以后再修正bug:a)为了使最小单位为0.01,最后结果精确到十分位即可,零头全部倒给最后一个人(或者从最后一个人那里出)b)如果有人说万一出现有人为0或者负数怎么办,这好办,一开始先给每人分配0.01作为“底钱”就好了。2. 的猜想是基于调查数据的,这点我非常赞赏。不过想提出一点意见(不好意思大过年的较真了哈哈):图2用线性回归做趋势分析是很好的,不过应该给出置信区间或p值等统计显著性指标。图3其实是有些误导的,因为你做的是一个累计平均,误差近似于,所以如果你把Confidence Band画出来也许会发现并没有显著偏离平均值。3. 对于这个问题,大家可能关心两个问题:a)算法怎么实现的?b)先拿好还是后拿好?我认为后一个问题比较好回答,而且顺便想指出的是,即使存在和次序相关的“bug”,也非常容易“修正”:每次生成完分配方案以后把顺序打乱即可。现在说说我是怎么分析这个问题的:1. 首先同样是采样。我从微信群里抓取了37次分红的结果,为了使样本具有可比性,我只筛选了分红人数为5的样本,数据(一共37行)大概长这样:
[,1] [,2] [,3] [,4] [,5][1,] 0.26 1.64 1.50 0.51 1.09[2,] 0.16 1.20 1.28 2.03 1.21[3,] 0.03 0.43 0.01 0.51 0.02[4,] 5.39 2.67 1.74 3.27 1.93[5,] 0.31 0.07 0.07 0.33 0.22[6,] 0.44 1.93 1.40 1.72 3.39...其中每一行是一次分红。例如:抽样的第三个红包总金额为1元,其中第2个人抽到了0.43元。2. 然后一个我认为合理的假设(其实可能大家都已经默认了)是:我们的分布是齐次的。记每个人分红的联合分布密度函数(joint pdf)为,其中是第个人分到的金额(在我们的数据中),而为总金额。那么齐次指的是:。用通俗的语言说一遍就是:如果你把总金额乘上一个倍数,新的分布和原来的分布是“相似”的。3. 有了齐次的假设,我们就可以把采集到的数据归一化(每一行除以它们的和),得到的每一个结果的意义是:每个人分到的钱占总金额的比例。4. 箱形图上图是37个样本的总结(横轴代表第几个人,纵轴是分到的比例)。从这幅图来看看不出啥,不过别急,这张图并不完全适合描述我们这个问题,因为每一个人的分红是相关的。4. 直方图没有评论。没有评论。5. 图上面我没看出啥明显的端倪,数字呢?五组的均值:0.....2062385另外给出协方差矩阵:
0. -0. -0.V2 -0.
0. -0. -0. -0.V3
0. -0. -0.V4 -0. -0. -0.
0. -0.V5 -0. -0. -0. -0.
0.协相关矩阵(以后会用到):
1.....1343338V2 -0.....2393172V3
0.....2286393V4 -0.....2859395V5 -0.....0000000我们做一个Wald test,看看我们的数据是不是满足零假设(五组的期望均为0.2),略去计算过程,Wald test statistic = 0.0878, p值约为1,说明没有显著证据拒绝零假设。因此回答了问题b)先拿好还是后拿好?——都一样(从目前数据看来)。6. 从经验分布反推模型是一个比较玄的事情,我们可以通过一些检验(正态检验、卡方检验)来从统计学上排除某个分布,但没有人能告诉你哪个分布是“对”的(All models are wrong, but some are useful. -- George E. P. Box)。可能和强迫症有关系,这个截断正态分布在我看来并不是一个漂亮的模型。狄利克雷分布(参见)可能是个更好的选择:它要求这K个随机变量分布在0~1之间,且它们的和为1,这正是我们想要的!进一步想,既然目前没有明显证据支持每个人分到的比例不相同,那就从零假设(相同)出发。对于狄利克雷分布而言,就是所有的a(公式编辑器突然坏了,所以不写tex了,想看的去Wiki上找)都相同,代入到页面中关于期望和方差的公式(K=5)得到E[Xi]=0.2,Var[Xi]=4/[25(5a+1)],Cor[Xi,Xj]=-0.25。和之前我们看到的数字(均值、方差、协相关)比是不是有一点点像?7. 这是拟合的结果,拟合出的系数a(分别)为1.....352875。我相信,如果有更多的数据,我们可以更有把握(power)地判断a是否有显著区别,或者说,第几个拿最好?我相信,如果有更多的数据,我们可以更有把握(power)地判断a是否有显著区别,或者说,第几个拿最好?
红包抢了很多,有种错觉,就是最后那一两个红包总是最佳手气。为了分析红包多少的分布,取了红包数量 &= 5 的 100 个红包,,其中红包份数为 5 份、10份和 20 份的占了 2/3(66 个),最多的一个红包有 22 份,这 100 个红包的份数分布如下:5:
——————
对每个红包 i ,统计分布。其中
为第 i 个抢到的钱数, 为红包总金额, 为红包平均金额。把结果再平均一下,得到下图:结论就是我想多了……
转。微信是采用什么样的算法做到的?简单百度了下,目前尚未有官方的说明,仅仅在知乎里有一个较为热门的讨论,链接戳这里
不过他们讨论的太过于深入,有掉坑之嫌。我按照自己的逻辑尝试了下,这个算法需要满足以下几点要求1、每个人都要能够领取到红包;2、每个人领取到的红包金额总和=总金额;3、每个人领取到的红包金额不等,但也不能差的太离谱,不然就没趣味;4、算法一定要简单,不然对不起腾讯这个招牌;正式编码之前,先搭建一个递进的模型来分析规律设定总金额为10元,有N个人随机领取:
则红包金额=X元;
为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数
第二个红包=10-第一个红包金额;
红包1=0.01至0.98之间的某个随机数
红包2=0.01至(10-红包1-0.01)的某个随机数
红包3=10-红包1-红包2
至此,规律出现啦!开始编码!header("Content-Type: text/charset=utf-8");//输出不乱码,你懂的
$total=10;//红包总额
$num=8;// 分成8个红包,支持8人随机领取
$min=0.01;//每个人最少能收到0.01元
for ($i=1;$i&$$i++)
$safe_total=$total-($num-$i)*$//随机安全上限
$money=mt_rand($min*100,$safe_total*100)/100;
$total=$total-$
echo '第'.$i.'个红包:'.$money.' 元,余额:'.$total.' 元 &br/&';
echo '第'.$num.'个红包:'.$total.' 元,余额:0 元';
输入一看,波动太大,这数据太无趣了!第1个红包:7.48 元,余额:2.52 元
第2个红包:1.9 元,余额:0.62 元
第3个红包:0.49 元,余额:0.13 元
第4个红包:0.04 元,余额:0.09 元
第5个红包:0.03 元,余额:0.06 元
第6个红包:0.03 元,余额:0.03 元
第7个红包:0.01 元,余额:0.02 元
第8个红包:0.02 元,余额:0 元
改良一下,将平均值作为随机安全上限来控制波动差header("Content-Type: text/charset=utf-8");//输出不乱码,你懂的
$total=10;//红包总额
$num=8;// 分成8个红包,支持8人随机领取
$min=0.01;//每个人最少能收到0.01元
for ($i=1;$i&$$i++)
$safe_total=($total-($num-$i)*$min)/($num-$i);//随机安全上限
$money=mt_rand($min*100,$safe_total*100)/100;
$total=$total-$
echo '第'.$i.'个红包:'.$money.' 元,余额:'.$total.' 元 &br/&';
echo '第'.$num.'个红包:'.$total.' 元,余额:0 元';
输出结果见下图第1个红包:0.06 元,余额:9.94 元
第2个红包:1.55 元,余额:8.39 元
第3个红包:0.25 元,余额:8.14 元
第4个红包:0.98 元,余额:7.16 元
第5个红包:1.88 元,余额:5.28 元
第6个红包:1.92 元,余额:3.36 元
第7个红包:2.98 元,余额:0.38 元
第8个红包:0.38 元,余额:0 元
如果你有更好更简单的算法,欢迎与我讨论。作者:Small链接:﹣﹣﹣﹣﹣ java version ﹣﹣﹣﹣﹣/**
* 微信红包分配算法
* @author Michael282694
public class wechat_money {
public static void main(String[] args) {
// TODO Auto-generated method stub
double total_ // 红包总金额
int total_ // 抢红包总人数
double min_ // 每个人最少能收到0.01元
total_money = 10.0;
total_people = 8;
min_money = 0.01;
for (int i = 0; i & total_people - 1; i++) {
int j = i + 1;
double safe_money = (total_money - (total_people - j) * min_money)
/ (total_people - j);
double tmp_money = (Math.random()
* (safe_money * 100 - min_money * 100) + min_money * 100) / 100;
total_money = total_money - tmp_
System.out.format("第 %d 个红包: %.2f 元,剩下: %.2f 元\n", j, tmp_money,
total_money);
System.out.format("第 %d 个红包: %.2f 元,剩下: 0 元\n", total_people,
total_money);
某一次的結果:第 1 个红包: 0.54 元,剩下: 9.46 元
第 2 个红包: 1.04 元,剩下: 8.42 元
第 3 个红包: 0.60 元,剩下: 7.83 元
第 4 个红包: 0.17 元,剩下: 7.66 元
第 5 个红包: 1.54 元,剩下: 6.11 元
第 6 个红包: 0.58 元,剩下: 5.53 元
第 7 个红包: 3.60 元,剩下: 1.93 元
第 8 个红包: 1.93 元,剩下: 0 元
因为保留两位小数时存在四舍五入,有时候所有金额相加会存在0.01元的误差(实际并不存在)。
从工程角度来说,红包分配算法需要简单粗暴的实现。楼上有人的算法过于复杂,第几个人领取都要面面俱到的计算,考虑因素太多,工程实现上真的没必要。其实只需要按照如下框架即可:1. 发红包时,按照设计的快速随机算法,将红包分好若干份。2. 按照设计的评估算法,对得到的红包分配进行校验。3. 如果校验不通过,如贫富差距过大,则重复随机分配。4. 如果若干次重复,如5次,则停止重复,就按照当前分配。5. 再有用户请求红包,直接队列化请求,再从红包序列中取出对应编号红包。上述方案的优势是:1. 只需“一次”计算。随机算法选择简单粗暴的即可,系统按照校验策略对其评价,不满足则有限次重复,直到满足或次数太多为止。2. 此后就只有读取。后续操作完全是读取缓存,无需密集计算。那么是不是还有更简单粗暴的方案呢?还是有的,那就是伪随机序列查表法。百万千万级别的红包请求,如果每次都按照真随机来计算,仍然会有不小的计算压力。索性预先计算得到若干伪随机分配方案,调用时只需要随机选择一个即可。举例来说,有人的红包是10元分配给5人,系统预先存有多种分配方案,如1,1,2,3,3,或1,1,2,2,4,请求时随机选取一个方案即可。当然,各种组合未必能穷尽,但是只需要让用户在有限次操作中觉得这是随机就够了。
微信红包的架构设计简介@来源于QCon某高可用架构群整理,整理朱玉华。背景:有某个朋友在朋友圈咨询微信红包的架构,于是乎有了下面的文字(有误请提出,谢谢)概况:2014年微信红包使用数据库硬抗整个流量,2015年使用cache抗流量。微信的金额什么时候算? 答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储。。 采取实时计算金额的考虑:预算需要占存储,实时效率很高,预算才效率低。实时性:为什么明明抢到红包,点开后发现没有? 答:2014年的红包一点开就知道金额,分两次操作,先抢到金额,然后再转账。 2015年的红包的拆和抢是分离的,需要点两次,因此会出现抢到红包了,但点开后告知红包已经被领完的状况。进入到第一个页面不代表抢到,只表示当时红包还有。分配:红包里的金额怎么算?为什么出现各个红包金额相差很大? 答:随机,额度在0.01和剩余平均值*2之间。 例如:发100块钱,总共10个红包,那么平均值是10块钱一个,那么发出来的红包的额度在0.01元~20元之间波动。当前面3个红包总共被领了40块钱时,剩下60块钱,总共7个红包,那么这7个红包的额度在:0.01~(60/7*2)=17.14之间。 注意:这里的算法是每被抢一个后,剩下的会再次执行上面的这样的算法(Tim老师也觉得上述算法太复杂,不知基于什么样的考虑)。这样算下去,会超过最开始的全部金额,因此到了最后面如果不够这么算,那么会采取如下算法:保证剩余用户能拿到最低1分钱即可。如果前面的人手气不好,那么后面的余额越多,红包额度也就越多,因此实际概率一样的。红包的设计 答:微信从财付通拉取金额数据郭莱,生成个数/红包类型/金额放到redis集群里,app端将红包ID的请求放入请求队列中,如果发现超过红包的个数,直接返回。根据红包的裸祭处理成功得到令牌请求,则由财付通进行一致性调用,通过像比特币一样,两边保存交易记录,交易后交给第三方服务审计,如果交易过程中出现不一致就强制回归。发性处理:红包如何计算被抢完? 答:cache会抵抗无效请求,将无效的请求过滤掉,实际进入到后台的量不大。cache记录红包个数,原子操作进行个数递减,到0表示被抢光。财付通按照20万笔每秒入账准备,但实际还不到8万每秒。通如何保持8w每秒的写入? 答:多主sharding,水平扩展机器。据容量多少? 答:一个红包只占一条记录,有效期只有几天,因此不需要太多空间。询红包分配,压力大不? 答:抢到红包的人数和红包都在一条cache记录上,没有太大的查询压力。一个红包一个队列? 答:没有队列,一个红包一条数据,数据上有一个计数器字段。有没有从数据上证明每个红包的概率是不是均等? 答:不是绝对均等,就是一个简单的拍脑袋算法。拍脑袋算法,会不会出现两个最佳? 答:会出现金额一样的,但是手气最佳只有一个,先抢到的那个最佳。每领一个红包就更新数据么? 答:每抢到一个红包,就cas更新剩余金额和红包个数。红包如何入库入账? 数据库会累加已经领取的个数与金额,插入一条领取记录。入账则是后台异步操作。入帐出错怎么办?比如红包个数没了,但余额还有? 答:最后会有一个take all操作。另外还有一个对账来保障。
看到这个问题特别找了几个群发了一下红包。。看了下分布,在我的抽样中。。超过2倍均值的红包出现概率在6%左右。。这个分布有很多种生成办法。某楼提到的截尾正态是个不错的实现。可能的方案由于红包个数N是确定的。所以可以生成N个均值是1,但是大于0的正态分布的随机数,如果不当心生成到小于0的就重新生成一次(形成截尾正态分布)然后以这N个随机数为比例分配红包。目前看不到明显的平衡策略,看了下滤波后的红包vs时间的数据先抢和后抢似乎是差不多的,高值有时出现在前面有时出现在后面。
建议按聊天的多少来发 聊天多的发得多聊天少的发得少 给那些在列表里从来不找你这时候来取的逼们一个狠狠的耳光
好吧春节不应该这么不和谐也没有意义也不是随机的可是我是这么想的。匿了
我想的算法是,以10个人分1元为例,想象把100个1分排成一列,这样中间就有99个可分割的地方,随机选9个这样就拆成10段。也就是说红包一开始就分配好了。其实就这么简单,不信可以自己跑测试,绝对分布和你们分析的差不多。另外我这边那些红包并没有后来者钱多的现象。
我的算法趋于平均值的,波动很小。每个红包先分配0.01.把剩下的根据波动值(最低0.01元)平均分成n份,每次随机给一个红包添加一份波动值。直到把所有的钱分完。
1.一个随机算法。2.计算第N个人的时候,要把前面N-1的人都抠出去。3.计算第N个人的时候,要为后面的人预留出最低金额的总额,比如、每个人一分钱。4.如果是最后一个人,那就不用算了,剩下的都是他的。至于领取时,怎么把用户和金额关联起来,实现起来就自由了,对锁的依赖越少越好。
/*下面是自己写的抢红包代码,亲测可用。支持拼手气红包和普通红包两种模式
简单说一下原理:因为不能有人分配到0元,所以预先给每个人分配0.01元,然后将总金额减去预先分配的n个0.01元然后再进行随机分配。使用JDK里的Math类中的random函数生成0~1之间的随机数,然后将每个随机数相加求和得到sum,然后将每个随机数乘上(cash/sum),分配到实际金额。
因为电脑在进制转换的时候不可避免的会出现round-off error,所以写了两个保留两位小数的method:一个是直接截掉两位小数之后的数字,不进行四舍五入,另一个是进行四舍五入的保留两位小数。
因为直接截取两位小数,然后进行多次运算之后一定会出现分配给每个红包的金额比初始总金额小的情况,所以将这部分误差分成n个0.01元,随机分配给每个红包,以实现前后总金额相等。(之所以不采用四舍五入是因为会出现无法预测的与总金额不符的情况,所以采用直接截取两位小数的方法,可以保证分配给每个红包的金额比初始总金额小)
该程序完全模拟微信红包,包括各种限定条件(微信的拼手气红包不支持100个以上的红包数,但是此程序没有添加这个限定,所以大家可以用任何大于0的整数测试该程序。)
提供给大家几个苛刻的情况测试此程序:
拼手气红包:
0.1元分配给10个红包
0.11元分配给10个红包
0.11111元分配给10个红包
99.99元分配给10个红包
99.99元分配给100个红包
0.09元分配给10个红包
10000元分配给2个红包
普通红包:
0.1元分配给10个红包
0.11元分配给10个红包
仅仅接触java语言6天时间,有些语句可能不成熟或者有更好的表示方法,欢迎各位指证!祝大家新年愉快*/
import java.util.*;
import java.math.*;
import java.text.*;
public class QiangHongBao
public static void main(String[] args)
int num = 0;// 红包的个数
double cash = 0;//总钱数
int pin = 0;//判断是否拼手气的临时变量
int MaxNo = 0;//记录最大值的位置
int MinNo = 0;//记录最小值的位置
while(true)
System.out.println("1.请问要发多少个红包?");
Scanner number = new Scanner(System.in);
num = number.nextInt();//读取用户输入,并存入num变量
if(num == 0)//如果用户输入了0
System.out.println("输入错误,请输入大于0的整数!" + "\n" + "请重新输入!" +
"\n");//返回警告
//System.exit(0);//结束程序
System.out.println();
double[] a = new double[num];//定义一个double型的有num个元素的数组
while(true)
System.out.println("2.请问要发多少钱?");
Scanner coin = new Scanner(System.in);
cash = coin.nextDouble();//读取用户输入,并存入cash变量
if((100*cash)%1 != 0)//如果用户输入了三位或更多位的小数
System.out.println("输入错误,请输入最多保留两位的小数" + "\n" + "请重新输入!"
+ "\n");//返回警告
//System.exit(0);//结束程序
else if((cash/num) & 0.01)//如果每个红包平均分到的金额小于0.01元
System.out.println("金额错误,单个红包金额不可小于0.01元,请调整金额和红包数
!" + "\n" + "请重新输入!" + "\n");//返回警告
//System.exit(0);//结束程序
else if((cash/num) & 200)//如果每个红包平均分到的金额大于200元
System.out.println("金额错误,单个红包金额不可大于200元,请调整金额和红包数
!" + "\n" + "请重新输入!" + "\n");//返回警告
//System.exit(0);//结束程序
System.out.println();
while(true)
System.out.println("是否设定为拼手气红包?(请输“1”或“2”,1代表是,2代表否)");
Scanner pi = new Scanner(System.in);
pin = Integer.parseInt(pi.nextLine());//读取用户输入,并存入pin变量
if(pin == 0)
System.out.println("选择错误,请选择1或2!" + "\n" + "请重新输入!" + "\n");//返回警
else if(pin & 2)
System.out.println("选择错误,请选择1或2!" + "\n" + "请重新输入!" + "\n");//返回警
if(pin == 1)
System.out.println("\n正在生成总金额为" + cash + "元的" + num + "个拼手气红包");
pinshouqiArray(a,cash);
printArray(a);
double sum2 = Math.round(sum(a)*100);
System.out.println(sum2/100);
int cash1 = (int)(cash * 100);
int sum1 = (int)(sum2);
int resi = cash1 - sum1;
for(int i = 0; i & i++)
a[(int)(Math.floor(a.length * Math.random()))] += 0.01;
sishewuru(a);
printArray(a);
double sum3 = Math.round(sum(a)*100);
System.out.println("共发出:" + sum3/100 + "元");
MaxNo = Max(a);
MinNo = Min(a,cash);
if(MaxNo == MinNo)
System.out.println("大家拿的都一样╮(╯▽╰)╭");
System.out.println("第" + MaxNo + "位童鞋手气最佳!");//显示手气最佳的人
System.out.println("第" + MinNo + "位童鞋请再接再厉!");//显示手气最差的人
else if(pin == 2)
System.out.println("\n正在生成总金额为" + cash + "元的" + num + "个普通红包");
if(cash * 100 / num != 1)
System.out.println("金额不能平均分配给每个红包,程序结束");
System.exit(0);
a = putongArray(a,cash);//普通红包,存入数组
printArray(a);//打印每个红包到屏幕
double sum3 = Math.round(sum(a)*100);
System.out.println("总金额:" + sum3/100);
public static double[] initial(double[] a)
for(int i = 0; i &= a.length-1; i++)
a[i] = 0.01;
public static void printArray(double[] a)//方法:打印数组到屏幕
System.out.print("结果:" + "\n");
for(int i = 0; i &= a.length-1; i++)
System.out.println("第" + (i+1) + "个红包里面有" + a[i] + "元");
public static double[] baoliu(double[] a)//保留两位小数,不要四舍五入
double b = 0;
double c = 0;
for(int i = 0; i & a. i++)
c = (Math.floor(100*b));//向下取整
public static double[] arraygenerate(double[] a)//产生随机数组
for(int i = 0; i &= a.length-1; i++)
a[i] = Math.random();
a = baoliu(a);
public static double[] pinshouqiArray(double[] a, double cash)
arraygenerate(a);//随机给数组中的每个元素分配一个0~1之间的小数
double sum = 0;//定义变量
sum = sum(a);
for(int i = 0; i &= a.length-1; i++)
a[i] *= ((cash-a.length*0.01)/sum);
a[i] += 0.01;
baoliu(a);
//返回数组
public static double[] sishewuru(double[] a)//保留两位小数,四舍五入
double b = 0;
double c = 0;
for(int i = 0; i & a. i++)
c = Math.round(100*b);//向下取整
public static double sum(double[] a)
double sum = 0;
for(int i = 0; i &= a.length-1; i++)
sum += a[i];//算出所有元素的总和
public static double[] putongArray(double[] a, double cash)//普通红包
for(int i = 0; i &= a.length-1; i++)
double temp = 0;
temp = Math.floor(cash * 10);//向下取整,为避免系统自动四舍五入导致超额的情况
temp /= 10;
a[i] = temp/a.//取平均值
//返回数组
public static int Max(double[] a)//求最大值的序号
double max = 0;
int recmax = 0;
for(int i = 0; i &= a.length-1; i++)
if(a[i] & max)
max = a[i];
recmax = i + 1;
//返回最大值的序号
public static int Min(double[] a, double cash)//求最小值的序号
double min = cash + 1;
int recmin = 0;
for(int i = 0; i &= a.length-1; i++)
if(a[i] & min)
min = a[i];
recmin = i + 1;
//返回最小值的序号
很多答案的技术方案没有考虑访问量。在极高峰值的时候(每分钟8亿次),最重要的是响应速度。所以红包的核心技术点是「用空间换时间」,也就是说发红包时就计算出所有红包面额,然后大家排队领取即可。具体的随机算法,需要仔细调整,瞎猜没有用的。
比如分给N个人。出N个数的随机数列{A1,A2,...An},加起来归一化之后就可以得到每份红包的占比,再乘以总数就得到了N分随机红包。
管它怎么实现的,大家除夕好,新年大吉。
核心算法就是随机数主要的需求是得出10个红包,同时有一个隐性条件,每个红包中都要有钱,即每个红包至少1分钱。如果是我会这么干(100块分成10个红包)先取10分钱出来,这样可以屏蔽有的红包没钱的问题。剩下9990分钱,把这9990分钱分成10份即可。9990分钱一字排开,用9块板子插到这些钱中间(插板子这事你们肯定都干过),每两块板子中有多少钱就是一个红包中的钱数了,再加上之前取出的1分钱就是最后的红包了。怎么找插板子的位置呢?取0到1之间的随机数乘9991就好了,重复做9次。第1块板之前的钱加1分就是第一个红包里的钱数,依此类推得出10个红包中的钱数。之后要测试这种方法是不是平均的分了。分个一万次,嗯,反正电脑不会累。回答完毕。P.S.微信的红包表现还挺好的 也就卡个10来分钟。。。想发的可以先塞钱,过10分钟再发
一个小小的想法,仅供参考^_^我的方法我称之为节点法。这样操作,以50元100个红包,平均每个红包0.5元为例。第一步,把100个红包自动分成10组,每组10个红包,给每组红包分配5元第二步,每组红包共5元,平均每个红包m元,m=0.5,给组内红包分配随机数,随机数的范围为(-(m-0.1)~+x),x的取值用来控制红包金额的最大值,同时还需满足,每组随机数之和为零第三步,当用户抽红包时随机调取一组红包,并为之分配一个随机数,用户获得的金额既0.5+随机数(因为随机数的最小值-0.4小于平均数,所以可以保障每个人都有钱可分)第四步,当下一个用户抽取红包时,继续抽取本组红包,同时从剩下的随机数中抽取一个随机数来确定金额第五步,直到本组红包抽完,下个用户从剩下的组中再选取一组和一个随机数抽取红包第六步重复以上步骤,直至所有红包抽完^_^ 此算法的优点1,保障所有的用户都有红包可抽(m-(m-0.1)=0.1>0)2,可以通过调节+x来方便的控制红包的最大金额,例如红包的平均值为m,我令+x=2m,则红包的最大金额为3m3,为什么称之为节点法呢?你们发现没有,红包是先抽完一组再抽另一组的,也就是说,到某个节点时,是满足本组红包的平均值为总平均值的,本题中便是,1~10用户抽到红包的平均值为0.5,11~20用户抽到的平均值也是0.5,21~30用户也是,以此类推,充分避免了某些前面的人抽到的全部是大额红包,后面的人都是0.1元的情况或者是前面都是0.1后面都是数额很大的情况

我要回帖

更多关于 表示感谢发多少红包 的文章

 

随机推荐