关于红包算法

前些天,在CSDN的微信订阅号里看到了一篇关于抢红包的算法。微信原文链接如下:

http://mp.weixin.qq.com/s?src=11&timestamp=1525155316&ver=849&signature=vG5ZSGeawMwaYdiV-KI5tWVVd-ZioSD9yjD8sVEdz8WgZPiN0ckqCFrj1dRarW4wRGNIVtDndK3zOD6rbLw60HBxjeZkR22n1qYUlBLOfgNcbzOTY8j*2mDhxb9tmUHh&new=1

这两天,数学建模算是告一段落,来看看这个算法吧。

假设红包的总金额为100元,10个人抢(都参与)。

对于小灰提出来的第一种方法,每次抢到的金额 = 随机区间 ( 0,  剩余金额 )。评论里很多人质疑第一种,觉得产生的金额随机且差别不大,先抢的人并不会优势很大。自己觉得应该是先抢得到的大金额的红包的几率更大,可既然有人质疑,那么就事实说话吧。

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class GrabRedEnvelope {
	//发红包算法,金额参数以分为单位
	public static List<Integer> grabRedEnvelope(int totalAmount,int totalPeopleNum){
		List<Integer> amountList = new ArrayList<Integer>();
		int restAmount=totalAmount;
		//int restPeopleNum=totalPeopleNum;
		Random random =new Random();	
		for(int i=0;i<totalPeopleNum-1;i++){
			//剩下的人抢剩下的钱,每个人抢的不少于一分钱
			int amount=random.nextInt(restAmount)+1;
			restAmount-=amount;
			//restPeopleNum--;
			amountList.add(amount);			
		}
		amountList.add(restAmount);
		return amountList;
		
	}
	

	public static void main(String[] args) {
		List<Integer> amountList =grabRedEnvelope(10000, 10);
		for(int amount : amountList){
			System.out.println("抢到金额:" + new BigDecimal(amount).divide(new BigDecimal(100)));
    }

	}

}

第一种方法,不需要变量剩余多少人,只是挨着分配剩余的钱数。运行了很多次,的确会出现,先抢的人得到的金额更大的情况。情况之一截图如下,(大多类似):

评论还有说,先随机出红包,再随机排序。那么出来的也只是对于上面金额差异很大的一组分配金额列表排序,还是有失公允。

再看看原文提到的二倍均值法。

剩余红包金额为M,剩余人数为N,则每次抢到的金额 = 随机区间 (0, M / N X 2)。它保证了每次每次随机金额的平均值是相等的。可是随机自由度低,算法原文已经很清晰了,不再赘述。

提出的第三种方法是线段切割法。当N个人一起抢总金额为M的红包时,我们需要做N-1次随机运算,以此确定N-1个切割点。随机的范围区间是(1, M)。原文没有给出算法,我试着写了一下

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class GrabRedEnvelope {
	//发红包算法,金额参数以分为单位,线段分割法O(∩_∩)O
	public static List<Integer> grabRedEnvelope(int totalAmount,int totalPeopleNum){
		List<Integer> amountPointList = new ArrayList<Integer>();
		List<Integer> sortedAmountList = new ArrayList<Integer>();
		int restAmount=totalAmount;
		Random random =new Random();
		int i=0;
		//n-1个不同切割点
		while(i<totalPeopleNum-1){
			//随机n-1个切割点
			System.out.println("抢到金额");
			int point=random.nextInt(restAmount)+1;
			restAmount-=point;
			amountPointList.add(point);
			i++;
			if(amountPointList.size()>0 ){
				for(int j=0;j<amountPointList.size();j++)	  
			  	{ 
					if (amountPointList.get(j) == point) { 
						amountPointList.remove(i); 
				        i--;       
					} 
			  	}
			}
		}
		//对切割点进行排序
		Collections.sort(amountPointList);
		Collections.sort(amountPointList, new Comparator() {
		 @Override
		public int compare(Object o1, Object o2) {
			   return new Double((String) o1).compareTo(new Double((String) o2));
			  }
		 });
		System.out.println(amountPointList.toString());
			
		//输出最终结果
		for(int temp=0;temp<amountPointList.size();temp++){
			if(temp==0)
				sortedAmountList.add(amountPointList.get(temp));
			else	
				sortedAmountList.add(amountPointList.get(temp)-amountPointList.get(temp-1));	
		}
		return sortedAmountList;
	}
	

	public static void main(String[] args) {
		List<Integer> amountList =grabRedEnvelope(10000, 10);
		for(int amount : amountList){
			System.out.println("抢到金额:" + new BigDecimal(amount).divide(new BigDecimal(100)));
    }

	}

}
O(∩_∩)O哈哈~果然有错误,改天改吧o(╥﹏╥)o
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值