C#实现抢红包算法的示例代码

目录
  • 二倍均值法(公平版)
  • 线段切割法(手速版)

二倍均值法(公平版)

发出一个固定金额的红包,由若干个人来抢,需要满足哪些规则?

1.所有人抢到金额之和等于红包金额,不能超过,也不能少于。

2.每个人至少抢到一分钱。

3.要保证所有人抢到金额的几率相等。

假设剩余红包金额为M,剩余人数为N,那么有如下公式:

每次抢到的金额 = 随机区间 (0, M / N × 2)

这个公式,保证了每次随机金额的平均值是相等的,不会因为抢红包的先后顺序而造成不公平。举个例子:

假设有10个人,红包总额100元。100/10×2 = 20, 所以第一个人的随机范围是(0,20 ),平均可以抢到10元。
假设第一个人随机到10元,那么剩余金额是100-10 = 90 元。90/9×2 = 20, 所以第二个人的随机范围同样是(0,20 ),平均可以抢到10元。
假设第二个人随机到10元,那么剩余金额是90-10 = 80 元。80/8×2 = 20, 所以第三个人的随机范围同样是(0,20 ),平均可以抢到10元。
以此类推,每一次随机范围的均值是相等的。

  static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                var list = DivideRedPackage(100* 100, 10);
                Console.WriteLine(string.Join(",", list));
                int count = 0;
                foreach (var item in list)
                {
                    count += item;
                }
                Console.WriteLine(count);
            }
            System.Console.ReadKey();
        }

        /// <summary>
        /// 产生红包数组
        /// </summary>
        /// <param name="cashCount">红包总金额,单位分</param>
        /// <param name="peopleNumber">红包人数</param>
        /// <returns></returns>
        static List<int> DivideRedPackage(int cashCount, int peopleNumber)
        {
            List<int> redPackageList = new List<int>();
            if (cashCount <= peopleNumber)
            {
                for (int i = 0; i < cashCount; i++)
                {
                    redPackageList.Add(1);
                }

                return redPackageList;
            }

            Random random   = new Random(GetRandomSeed());
            int    restCash = cashCount, restPeople = peopleNumber;
            for (int i = 0; i < peopleNumber - 1; i++)
            {
                var cash = random.Next(1, restCash / restPeople * 2);
                restCash -= cash;
                restPeople--;
                redPackageList.Add(cash);
            }
            redPackageList.Add(restCash);
            return redPackageList;
        }

例如,产生的结果如下:

1960,189,234,1763,1211,1236,1340,53,1652,362
10000
1032,1380,456,1885,608,857,1541,452,1273,516
10000
976,955,749,936,1990,1177,781,325,527,1584
10000
794,935,272,216,2034,522,455,2313,2260,199
10000
1376,1539,1292,614,443,1874,889,544,821,608
10000
914,15,877,1738,604,932,321,983,3106,510
10000
659,791,800,1066,788,908,991,2473,495,1029
10000
1256,733,1385,667,1192,1237,455,105,2121,849
10000
1941,1173,567,1280,1558,618,183,644,133,1903
10000
1313,735,1198,1173,1288,522,1879,1155,59,678
10000

上述示例中需注意,Random是一个伪随机数生成器,在大多数 Windows 系统上,Random 类 (System) | Microsoft Docs 15 毫秒内创建的对象可能具有相同的种子值。因此,如果New Random在循环中使用,就必须提供随机的种子值。我们可以使用RNGCryptoServiceProvider 类 (System.Security.Cryptography) | Microsoft Docs类产生随机树种子。具体代码如下:

        /// <summary>
        /// 产生加密的随机数种子值
        /// </summary>
        /// <returns></returns>
        static int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng =
                new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }

线段切割法(手速版)

算法思路如下:

线段分割法就是把红包总金额想象成一条线段,而每个人抢到的金额,则是这条主线段所拆分出的子线段。

当N个人一起抢红包的时候,就需要确定N-1个切割点。

因此,当N个人一起抢总金额为M的红包时,我们需要做N-1次随机运算,以此确定N-1个切割点。

随机的范围区间是(1, M)。当所有切割点确定以后,子线段的长度也随之确定。这样每个人来抢红包的时候,只需要顺次领取与子线段长度等价的红包金额即可。

需要注意一下两点:

1.每个人至少抢到一分钱。

2.分割的线段如果重复需要重新切割

具体代码如下:

    class Program
    {
        static List<int> DivideRedPackage(int cashCount, int peopleNumber)
        {
            List<int> redPackageList = new List<int>();
            if (cashCount <= peopleNumber)
            {
                for (int i = 0; i < cashCount; i++)
                {
                    redPackageList.Add(1);
                }
                return redPackageList;
            }

            Random    random     = new Random(GetRandomSeed());
            int       restPeople = peopleNumber;
            List<int> lineList   = new List<int>();
            while (restPeople > 1)
            {
                var line = random.Next(1, cashCount);
                if (lineList.Contains(line) == false)
                {
                    lineList.Add(line);
                    restPeople--;
                }
            }
            lineList.Sort();

            redPackageList.Add(lineList[0]);
            for (int i = 0; i < peopleNumber - 2; i++)
            {
                var cash = lineList[i + 1] - lineList[i];
                redPackageList.Add(cash);
            }
            redPackageList.Add(cashCount - lineList[lineList.Count - 1]);
            return redPackageList;
        }
        static int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng =
                new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                var list = DivideRedPackage(100 * 100, 10);
                Console.WriteLine(string.Join(",", list));
                int count = 0;
                foreach (var item in list)
                {
                    count += item;
                }
                Console.WriteLine(count);
            }
            System.Console.ReadKey();
        }
    }

输出结果如下:

409,2233,1843,546,983,679,1621,460,369,857
10000
50,472,281,603,577,1007,3929,38,591,2452
10000
194,1241,675,209,3507,1714,1199,596,313,352
10000
2127,578,16,2413,1332,586,91,260,465,2132
10000
1015,1421,963,626,3031,955,171,1112,60,646
10000
118,352,1062,1128,8,374,1879,1707,1755,1617
10000
2805,592,391,90,1468,392,2201,40,1426,595
10000
145,251,2910,59,1065,235,2761,997,1564,13
10000
814,1725,1886,39,696,202,44,992,3099,503
10000
828,1281,2402,579,380,2246,154,855,564,711
10000

到此这篇关于C#实现抢红包算法的示例代码的文章就介绍到这了,更多相关C# 抢红包算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java抢红包的红包生成算法

    马上过年了.过年微信红包很火,最近有个项目也要做抢红包,于是写了个红包的生成算法. 红包生成算法的需求 预先生成所有的红包还是一个请求随机生成一个红包 简单来说,就是把一个大整数m分解(直接以"分为单位,如1元即100)分解成n个小整数的过程,小整数的范围是[min, max]. 最简单的思路,先保底,每个小红包保证有min,然后每个请求都随机生成一个0到(max-min)范围的整数,再加上min就是红包的钱数. 这个算法虽然简单,但是有一个弊端:最后生成的红包可能都是min钱数的.也就是说可能

  • Javascript网页抢红包外挂实现分享

    一开始用Firefox加Firebug/YSlow插件分析,但是firefox不能运行自定义的javascript,好像还要装什么插件.于是转用chrome,发现chrome还是不错的,直接写个javascript就可以当作插件安装了. 中间淘宝还改过几次脚本,当然每次都是大同小异.佩服下苦逼的淘宝程序员,周末还要加班改脚本. 附录是我写的一个版本的脚本,直接调用 Volcano.BrickRate=1.0; Volcano.Brick.getLottery(KISSY); KISSY是一个类似

  • IOS 实现微信自动抢红包(非越狱IPhone)

    iOS微信自动抢红包(非越狱) 现在微信红包很流行,尤其在微信群里发红包,如果没有及时抢红包,根本抢不到,于是就想是不是能写个插件之类的实现自动抢红包呢,经过在网上查询资料,实现了该功能,如下: 微信红包 前言:最近笔者在研究iOS逆向工程,顺便拿微信来练手,在非越狱手机上实现了微信自动抢红包的功能. 题外话:此教程是一篇严肃的学术探讨类文章,仅仅用于学习研究,也请读者不要用于商业或其他非法途径上,笔者一概不负责哟~~ 好了,接下来可以进入正题了! 此教程所需要的工具/文件 yololib cl

  • Java实现抢红包功能

    本文实例为大家分享了Java实现抢红包功能的具体代码,供大家参考,具体内容如下 关键思想: 1.抢红包涉及多人并发操作,需要做好同步保证多线程运行结果正确. 2.由于同时在线人数大,从性能方面考虑,玩家的发红包请求不必及时响应,而由服务端定时执行发红包队列. 下面是主要的代码和实现逻辑说明 1.创建一个类,表示红包这个实体概念.直接采用原子变量保证增减同步.Java的原子变量是一种精度更细的同步机制,在高度竞争的情况下,锁的性能将超过原子变量的性能,但在更真实的竞争情况,原子变量享有更好的性能.

  • java模拟微信抢红包的实例代码

    java简单模拟微信抢红包功能,本例发100元红包,有10个人抢,为了尽可能的公平,每个人的红包金额都要随机(保证结果的不确定性,本例抢红包的次序与红包金额匹配也随机),就是不能出现部分红包偏大部分偏小的情况,在区间0~100上随机生成9个节点,加0和100共11个节点按从小到大排序,各节点之间的差值就是红包金额,保证了红包金额之和等于100. public static void main(String[] args) { // 发100元红包,10人抢 // TODO Auto-genera

  • Android实现QQ抢红包插件

    又想到快要过年了,到时候还不知道群里要发好多红包,所以我将之前在网上宕的一份微信抢红包的代码修改了一下,实现了QQ抢红包!可以支持抢QQ拼手气红包,普通红包,口令红包,现在再也不怕20年单身手速的人跟我抢红包了! 先看测试效果图: 1.抢QQ口令红包  可以看见,只要红包一发出,自动填写口令并发出,帮你将红包抢到手! 2.抢QQ拼手气红包 拼手气红包也是一样,只要红包一发出,自动帮你把红包抢到手,是不是很爽的感觉? 3.抢QQ好友发送的红包 只要好友或者群里的人把红包一发出,就会第一时间让你抢到

  • 教你一步步实现Android微信自动抢红包

    本文介绍微信自动抢红包的实现方法,主要实现以下几个功能: 1.自动拆开屏幕上出现的红包 2.处于桌面或聊天列表时接收到红包信息时自动进入聊天界面并拆红包 3.日志功能,记录抢红包的详细日志 实现原理 1.利用AccessibilityService辅助服务,监测屏幕内容,实现自动拆红包的目的. 2.利用ActiveAndroid数据库简单记录红包日志 3.利用preference实现监控选项纪录 最终界面 抢红包核心代码 AccessibilityService配置 android:access

  • C#实现抢红包算法的示例代码

    目录 二倍均值法(公平版) 线段切割法(手速版) 二倍均值法(公平版) 发出一个固定金额的红包,由若干个人来抢,需要满足哪些规则? 1.所有人抢到金额之和等于红包金额,不能超过,也不能少于. 2.每个人至少抢到一分钱. 3.要保证所有人抢到金额的几率相等. 假设剩余红包金额为M,剩余人数为N,那么有如下公式: 每次抢到的金额 = 随机区间 (0, M / N × 2) 这个公式,保证了每次随机金额的平均值是相等的,不会因为抢红包的先后顺序而造成不公平.举个例子: 假设有10个人,红包总额100元

  • Java实现8种排序算法的示例代码

    冒泡排序 O(n2) 两个数比较大小,较大的数下沉,较小的数冒起来. public static void bubbleSort(int[] a) { //临时变量 int temp; //i是循环次数,也是冒泡的结果位置下标,5个数组循环5次 for (int i = 0; i < a.length; i++) { //从最后向前面两两对比,j是比较中下标大的值 for (int j = a.length - 1; j > i; j--) { //让小的数字排在前面 if (a[j] <

  • JAVA用递归实现全排列算法的示例代码

    求一个n阶行列式,一个比较简单的方法就是使用全排列的方法,那么简述以下全排列算法的递归实现. 首先举一个简单的例子说明算法的原理,既然是递归,首先说明一下出口条件.以[1, 2]为例 首先展示一下主要代码(完整代码在后面),然后简述 //对数组array从索引为start到最后的元素进行全排列 public void perm(int[]array,int start) { if(start==array.length) { //出口条件 for(int i=0;i<array.length;i

  • c# 实现KMP算法的示例代码

    KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法).KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息.KMP算法的时间复杂度O(m+n) . 实现方式就不再这里献丑了,网上很多讲解,此处只是记录下c#实现的代码. public class KMP { public

  • python实现经典排序算法的示例代码

    以下排序算法最终结果都默认为升序排列,实现简单,没有考虑特殊情况,实现仅表达了算法的基本思想. 冒泡排序 内层循环中相邻的元素被依次比较,内层循环第一次结束后会将最大的元素移到序列最右边,第二次结束后会将次大的元素移到最大元素的左边,每次内层循环结束都会将一个元素排好序. def bubble_sort(arr): length = len(arr) for i in range(length): for j in range(length - i - 1): if arr[j] > arr[j

  • Python实现七大查找算法的示例代码

    查找算法 -- 简介 查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素.     查找表(Search Table):由同一类型的数据元素构成的集合     关键字(Key):数据元素中某个数据项的值,又称为键值     主键(Primary Key):可唯一的标识某个数据元素或记录的关键字 查找表按照操作方式可分为:         1.静态查找表(Static Search Table):只做查找操作的查找表.它的主要操作是:         ①

  • C#实现一阶卡尔曼滤波算法的示例代码

    //FilterKalman.cs namespace FusionFiltering { public class FilterKalman { private double A = 1; private double B = 0; private double H = 1; private double R; private double Q; private double cov = double.NaN; private double x = double.NaN; public Fil

  • Java实现查找算法的示例代码(二分查找、插值查找、斐波那契查找)

    目录 1.查找概述 2.顺序查找 3.二分查找 3.1 二分查找概述 3.2 二分查找实现 4.插值查找 4.1 插值查找概述 4.2 插值查找实现 5.斐波那契查找 5.1 斐波那契查找概述 5.2 斐波那契查找实现 5.3 总结 1.查找概述 查找表: 所有需要被查的数据所在的集合,我们给它一个统称叫查找表.查找表(Search Table)是由同一类型的数据元素(或记录)构成的集合. 查找(Searching): 根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录).

  • Python和Matlab实现蝙蝠算法的示例代码

    目录 1前言 2 蝙蝠算法原理细讲 3 详细步骤 4Python实现 4.1代码 4.2结果 5Matlab实现 5.1 代码 5.2 结果 5.3 展望 1 前言 蝙蝠算法是2010年杨教授基于群体智能提出的启发式搜索算法,是一种搜索全局最优解的有效方法.该算法基于迭代优化,初始化为一组随机解,然后迭代搜寻最优解,且在最优解周围通过随机飞行产生局部新解,加强局部搜索速度.该算法具有实现简单.参数少等特点. 该算法主要用于目标函数寻优,基于蝙蝠种群利用产生的声波搜索猎物和控制飞行方向的特征来实现

  • Java实现雪花算法的示例代码

    一.介绍 SnowFlow算法是Twitter推出的分布式id生成算法,主要核心思想就是利用64bit的long类型的数字作为全局的id.在分布式系统中经常应用到,并且,在id中加入了时间戳的概念,基本上保持不重复,并且持续一种向上增加的方式. 在这64bit中,其中``第一个bit是不用的,然后用其中的41个bit作为毫秒数,用10bit作为工作机器id,12bit`作为序列号.具体如下图所示: 第一个部分:0,这个是个符号位,因为在二进制中第一个bit如果是1的话,那么都是负数,但是我们生成

随机推荐