m个人抢一个手气红包
算法思路:
Q(n) = rand(0.01,2*R(n-1)/(m-n)-0.01)
Q(n): 第n个红包的金额
R(n-1): 第n-1个红包分配后的余额

实现思路,将金额最小额度定为1分,输入金额*100为以分为单位的整数

package main

import (
    "fmt"
    "math/rand"
    "time"
)

const (
    MaxAmount int = 200 * 100
    MinAmount     = 1
)

type redPack struct {
    Amount int
    Number int
}

func NewRedPack(amount int, number int) (*redPack, error) {
    if number < 1 {
        return nil, fmt.Errorf("number error")
    }
    if amount < MinAmount*number || amount > MaxAmount*number {
        return nil, fmt.Errorf("amount error")
    }
    return &redPack{
        Amount: amount,
        Number: number,
    }, nil
}

func (rp *redPack) calcArr() []int {
    remain := rp.Amount
    arr := make([]int, 0, rp.Number)

    for i := 0; i < rp.Number; i++ {
        if i == rp.Number-1 {
            arr = append(arr, remain)
            break
        }
        n := rp.getOne(remain, i)
        arr = append(arr, n)
        remain -= n
    }

    return arr
}

func (rp *redPack) getOne(remain int, i int) int {
    return 1 + rand.Intn(2*remain/(rp.Number-i)-1)
}

func main() {
    rand.Seed(time.Now().UnixNano())
    arr := [][2]int{
        {1, 1},
        {10, 5},
        {100, 7},
        {10000, 9},
    }

    for i, v := range arr {
        rp, _ := NewRedPack(v[0], v[1])
        if rp != nil {
            vs := rp.calcArr()
            fmt.Println(i, ": ", vs)
            if len(vs) != rp.Number {
                fmt.Println(i, ": arr len not eq number")
            }

            s := 0
            for j := range vs {
                s += vs[j]
            }

            if s != rp.Amount {
                fmt.Println(i, ": total not eq amount")
            }
        }
    }
}

JackLuo_Gopher
1 声望0 粉丝