Go代码实现 拼手气红包(二倍均值法)

本文介绍了一种基于二倍均值法的红包分配算法,确保每人至少0.01元,金额平均分散。通过实例演示和代码实现,讨论了其公平性和潜在问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

仅个人笔记,欢迎交流指正

概念

红包主要有三点限制

  1. 抢到的总额 = 红包的总额,不能多也不能少了
  2. 最小值是0.01元,即每个人都有份
  3. 每个人抢到的红包金额,尽量平均

实现逻辑

  • 假设总金额是M元,N个人,每次抢的金额=(0, (M/N) *2)

  • 比如,金额100,人数10,第一个人抢的金额是 (0,20),抢到的数值,根据正态分布,应该是10左右,远低于10的概率很小,同样远大于10的概率和很小,这里假设第一个人抢到的数值是10;

  • 第二个人抢的金额是(0,90/9*2)=(0,20),同第一个人,第二个人红包金额也应该是10附近;剩下的人,以此类推。

提醒
参考的文章说这个算法不是完美的,假如第一个人抢到15,第二个人的范围是(0,18.89),假如第二个人又抢到很高,那对后面的人是不利的

代码实现

package main

import (
	"errors"
	"math/rand"
)

//RED_PACKET_MIN_MONEY 红包最小金额(单位:分)
const RED_PACKET_MIN_MONEY = 1

//RedPacketModel 红包信息实体
type RedPacketModel struct {
	count          int64   //红包个数
	money          int64   //红包金额(单位:分)
	remainCount    int64   //剩余红包个数
	remainMoney    int64   //剩余红包金额(单位:分)
	bestLuckMoney  int64   //手气最佳金额(单位:分)
	bestLuckIndex  int64   //手气最佳索引位置
	historyRewards []int64 //历史红包记录
}

/*
CreateRedPacket
@Desc 	生成红包
@Param 	count int64	红包个数
@Param 	money int64	红包金额
*/
func CreateRedPacket(count, money int64) (res *RedPacketModel, err error) {
	if count <= 0 || money <= 0 || money < count*RED_PACKET_MIN_MONEY {
		err = errors.New("parameter error")
		return
	}

	res = &RedPacketModel{
		count:          count,
		money:          money,
		remainCount:    count,
		remainMoney:    money,
		bestLuckMoney:  0,
		bestLuckIndex:  0,
		historyRewards: nil,
	}

	return
}

/*
Open
@Desc 	拆红包(二倍均值法)
@Return money 	int64	本地拆红包获得金额
@Return res 	bool	拆红包失败,红包已经被抢光
*/
func (r *RedPacketModel) Open() (money int64, res bool) {
	//检测红包是否被抢光
	if r.Check() {
		return
	}

	//最后一个红包
	if r.remainCount == 1 {
		money = r.remainMoney
	} else {
		//最大可用金额 = 剩余红包金额 - 后续多少个没拆的包所需要的保底金额
		//目的是为了保证后续的包至少都能分到最低保底金额,避免后续未拆的红包出现金额0
		maxCanUseMoney := r.remainMoney - RED_PACKET_MIN_MONEY*r.remainCount

		//2倍均值基础金额
		maxAvg := maxCanUseMoney / r.remainCount

		//2倍均值范围数额
		maxMoney := maxAvg*2 + RED_PACKET_MIN_MONEY

		//随机红包数额
		money = rand.Int63n(maxMoney) + RED_PACKET_MIN_MONEY
	}

	//手气最佳
	if money > r.bestLuckMoney {
		r.bestLuckMoney = money
		r.bestLuckIndex = r.count - r.remainCount
	}

	res = true
	r.remainMoney -= money
	r.remainCount--
	r.historyRewards = append(r.historyRewards, money)
	return
}

/*
Check
@Desc 校验红包是否被抢完
*/
func (r *RedPacketModel) Check() bool {
	return r.remainCount == 0
}

参考

  • 参考:https://www.yisu.com/zixun/310871.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值