一、模拟客户需求

1.1 客户A需求:要求每次都按照下图的概率随机,数量不限,每个用户只能抽一次,抽奖结果的分布与抽奖概率近似。

1.2 客户B需求:固定奖项10个,抽奖次数不限,每个用户只能抽一次,抽完为止,抽奖结果必须是固定的那几个奖项。

二、需求分析

算法1:对于客户A,由于抽奖次数无限次,出奖分布遵守中奖概率设定值。所以必须在用户每一次的抽奖行为之前都按照中奖概率随机出就可以了,这样随着样本的增多,概率分布越来越趋近于设定的抽奖概率。

算法2:对于客户B,由于奖项固定,需要将奖项硬编码(或者存储到DB),奖项抽出来一个就将该奖项从列表中删除。奖项就抽完后就直接返回未中奖。

三、算法实现

3.1先定义个类,用于存储奖项和概率的关系:

//算法1.每次都完全随机的算法
//作者:deepleo
//博客:http://www.deepleo.com/
//邮箱:yemor@qq.com
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RandomAlgorithm
{
    /// <summary>
    /// 奖品
    /// </summary>
    public class Prize
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { set; get; }
        /// <summary>
        /// 中奖概率
        /// </summary>
        public decimal Probability { set; get; }
    }
}

3.2 实现算法1

//算法1.每次都完全随机的算法
//作者:deepleo
//博客:http://www.deepleo.com/
//邮箱:yemor@qq.com
using System;
using System.Collections.Generic;

namespace RandomAlgorithm
{
    public class EveryRandomAlgo
    {
        public List<Prize> Prizes
        {
            private set;
            get;
        }
        public EveryRandomAlgo(List<Prize> prizes)
        {
            this.Prizes = prizes;
        }

        /// <summary>
        /// 随机下一次奖品
        /// </summary>
        /// <returns></returns>
        public string Next()
        {
            long tick = DateTime.Now.Ticks;
            Random ran = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));
            var rnum = ran.Next(0, 9999);//将0~100映射到0~10000,提高精度到小数点后2位;生成随机数rnum;
            //Console.WriteLine(rnum);
            var randomProbability = (decimal)rnum / 100;//再换算为0~100范围
            var target = 0;//命中index
            var end = Prizes[0].Probability;
            for (int k = -1; k < Prizes.Count - 1; k++)
            {
                var min = k < 0 ? 0 : Prizes[k].Probability;//最小中奖概率
                if (randomProbability >= min && randomProbability <= end)//随机出来的中奖概率位于中奖概率区间内
                {
                    target = k + 1;
                    break;
                }
                end += Prizes[k + 1].Probability;//最大中奖概率累计值
            }
            return Prizes[target].Name;
        }
    }
}

 3.3 实现算法2

//算法2.从数据表中随机取出一条记录的伪随机算法
//作者:deepleo
//博客:http://www.deepleo.comchuangshi88.cn/
//邮箱:yemor@qq.com

using System.Collections.Generic;

namespace RandomAlgorithm
{
    public class DefineByDBAlgo
    {
        public List<Prize> Prizes
        {
            private set;
            get;
        }
        private Queue<string> _dbRecords;//存储在数据表中的奖项记录数据
        public DefineByDBAlgo(List<Prize> prizes)
        {
            this.Prizes = prizes;
            _dbRecords = new Queue<string>();
            //按照中奖概率初始化奖项数据
            _dbRecords.Enqueue(Prizes[0].Name);
            _dbRecords.Enqueue(Prizes[0].Name);
            _dbRecords.Enqueue(Prizes[0].Name);
            _dbRecords.Enqueue(Prizes[0].Name);
            _dbRecords.Enqueue(Prizes[0].Name);
            _dbRecords.Enqueue(Prizes[1].Name);
            _dbRecords.Enqueue(Prizes[1].Name);
            _dbRecords.Enqueue(Prizes[1].Name);
            _dbRecords.Enqueue(Prizes[1].Name);
            _dbRecords.Enqueue(Prizes[2].Name);

        }

        /// <summary>
        /// 随机下一次奖品
        /// </summary>
        /// <returns></returns>
        public string Next()
        {
            if (_dbRecords != null && _dbRecords.Count > 0)
            {
                lock (_dbRecords)
                {
                    var random = _dbRecords.Dequeue(yxin7.com );//这里直接取出最上面的那一条记录。保证出奖顺序与数据库记录一致,如果要随机,只需要更改数据库记录顺序或者这里使用随机Index
                    return random;
                }
            }
            return "";
        }
    }
}

3.4 调用代码

//摘要:抽奖随机算法
//作者:deepleo
//博客:http://www.deepleo.comsbsbo.cc/
//邮箱:yemor@qq.com

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RandomAlgorithm
{
    class Program
    {
        static void Main(string[] args)
        {

            var prizes = new List<Prize>();
            prizes.Add(new Prize { Name = "三等奖50%", Probability = 50 });
            prizes.Add(new Prize { Name = "二等奖40%", Probability = 40 });
            prizes.Add(new Prize { Name = "一等奖10%", Probability = 10 });
            var algo1 = new EveryRandomAlgo(prizes);
            var result1 = new Dictionary<string, int>();
            var count = 5000;
            for (int i = 0; i < count; i++)
            {
                var next = algo1.Next();
               // Console.WriteLine("【{0}】算法1随机结果:{1}", i + 1, string.IsNullOrEmpty(next) ? "奖项已发完" : next);
                if (!result1.Keys.Any(x => x == next))
                {
                    result1.Add(next, 1);
                }
                else
                {
                    result1[next]++;
                }
                Thread.Sleep(1);
            }
            foreach (var key in result1.Keys)
            {
                Console.WriteLine("算法1随最终结果:{0}:{1}个", key, result1[key].ToString());
            }
            Console.WriteLine("=====================================");
            var algo2 = new DefineByDBAlgo(prizes);
            var result2 = new Dictionary<string, int>();
            for (int i = 0; i < count; i++)
            {
                var next = algo2.Next();
                //Console.WriteLine("【{0}】算法2随机结果:{1}", i + 1, string.IsNullOrEmpty(next110shenbo.cc) ? "奖项已发完" : next);
                if (!result2.Keys.Any(x => x == next))
                {
                    result2.Add(next, 1);
                }
                else
                {
                    result2[next]++;
                }
            }
            foreach (var key in result2.Keys)
            {
                Console.WriteLine("算法2随最终结果:{0}:{1}个", key, result2[key].ToString());
            }
            Console.ReadKey();
        }

    }

}

四、实验结果

1. 抽奖次数为10次的实验结果:

算法1,二等奖和三等奖的个数分别为:3,7。与设定的中奖概率偏差较大。

算法2,符合预期(由于将所有的奖项都放在最上面,所以奖项都抽出来了)。

2.抽奖次数为100次的实验结果:

算法1,二等奖和三等奖的个数分别为:57,43。与设定的中奖概率偏差较小,已经比较接近设定值。

算法2,符合预期,后面的99个由于奖项已经被抽完,所以都是未中奖的。

3.抽奖次数为1000次的实验结果:

算法1,二等奖和三等奖的个数分别为:497,503。与设定的中奖概率偏差非常接近了。

算法2,符合预期,后面的990个由于奖项已经被抽完,所以都是未中奖的。

五、总结

实际上这是一个比较简单的算法,唯一需要注意的的是:在构造Random对象时如果seed是一样的就很容易产生随机出来的结果是一样的。

所以代码中Thread.Sleep(1);以保证随机的结果分布均匀,但是这样又限制了算法1的出奖速度,不知道各位有没有更好的解决方案。

源代码下载:博客园下载地址

抽奖随机算法的技术探讨与C#实现的更多相关文章

  1. 微信红包中使用的技术:AA收款+随机算法

    除夕夜你领到红包了吗?有的说“我领了好几K!”“我领了几W!” 土豪何其多,苦逼也不少!有的说“我出来工作了,没压岁钱了,还要发红包”.那您有去抢微信红包吗?微信群中抢“新年红包”春节爆红.618微信 ...

  2. 权重随机算法的java实现

    一.概述 平时,经常会遇到权重随机算法,从不同权重的N个元素中随机选择一个,并使得总体选择结果是按照权重分布的.如广告投放.负载均衡等. 如有4个元素A.B.C.D,权重分别为1.2.3.4,随机结果 ...

  3. java实现权重随机算法

    权重随机算法在抽奖,资源调度等系统中应用还是比较广泛的,一个简单的按照权重来随机的实现,权重为几个随机对象(分类)的命中的比例,权重设置越高命中越容易,之和可以不等于100: 简单实现代码如下: im ...

  4. 七雄Q传封包辅助技术探讨回忆贴

    前言 网页游戏2013年左右最火的类型最烧钱游戏,当年的我也掉坑了.为了边玩还满足码农精神我奋力的学习如何来做外挂.2013年我工作的第二个年头.多一半…介绍下游戏<七雄Q传>是北京游戏谷 ...

  5. 权重随机算法Java实现

    权重随机算法在抽奖,资源调度等系统中应用还是比较广泛的,一个简单的按照权重来随机的实现,权重为几个随机对象(分类)的命中的比例,权重设置越高命中越容易,之和可以不等于100: 简单实现代码如下: ? ...

  6. POJ 3318 Matrix Multiplication(随机算法)

    题目链接 随机算法使劲水...srand((unsigned)time(0))比srand(NULL)靠谱很多,可能是更加随机. #include <cstdio> #include &l ...

  7. hdu 4712 (随机算法)

    第一次听说随机算法,在给的n组数据间随机取两个组比较,当随机次数达到一定量时,答案就出来了. #include<stdio.h> #include<stdlib.h> #inc ...

  8. hdu 4712 Hamming Distance ( 随机算法混过了 )

    Hamming Distance Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) ...

  9. HDU4712+随机算法

    随机算法 求n个20位的2进制串的MinDist. Dist:两个串的异或结果中1的个数 /* 随机算法 */ #include<algorithm> #include<iostre ...

随机推荐

  1. Server-U_详细配置

    1.首先绿化 Server-U,运行 2.打开Server-U自动弹出如下图:如果不自动弹出,那点击界面上的 新建域  ------ 先有域再有用户,用户在域里面 4. 输入“名称”和“说明”,其中“ ...

  2. (C++)STL排序函数sort和qsort的用法与区别

    主要内容: 1.qsort的用法 2.sort的用法 3.qsort和sort的区别 qsort的用法: 原 型: void qsort(void *base, int nelem, int widt ...

  3. TL-WR703 USB不稳定/当前的总结

    http://see.sl088.com/wiki/WR703_USB%E4%B8%8D%E7%A8%B3%E5%AE%9A/%E5%BD%93%E5%89%8D%E7%9A%84%E6%80%BB% ...

  4. System.Runtime.InteropServices.COMException (0x800706BA) 解决方法

    提示“操作失败:无法获取MAC地址.”错误的解决方法. .NET 获取 MAC地址可能会遇到   System.Runtime.InteropServices.COMException (0x8007 ...

  5. CSS3+Js制作的一款响应式导航条

    今天制作了一个响应式导航条,能够自动随着不同的屏幕分辨率或浏览器窗口大小的不同而改变导航条的样式,这里主要用到的就是CSS3的Media Query.具体可以查看浅谈响应式布局这篇文章,这里就不花费大 ...

  6. C# DataGridView中合并单元格

    /// 合并GridView列中相同的行 /// /// GridView对象 /// 需要合并的列 public static void GroupRows(GridView GridView1, ...

  7. bzoj 2435: [Noi2011]道路修建 树上 dp

    2435: [Noi2011]道路修建 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  8. VK Cup 2015 - Round 2 (unofficial online mirror, Div. 1 only) E. Correcting Mistakes 水题

    E. Correcting Mistakes Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset ...

  9. C#中正则表达式进行忽略大小写的字符串替换

    在C#里要进行忽略大小写的字符串替换,用string的Replace是很难做到的,即使花了天大的力气做到了,效率仍然是很低的,正确的方法应该是使用正则表达式. 要使用正则表达式,首先需要引用命名空间: ...

  10. 无线网卡的查看与配置——iw,iwconfig,ethtool

    摘要:在linux上,我们经常需要把一台笔记本设置成一个共享wifi上网的路由器.如果我们需要把本机配置成一台无线AP,就需要查看网卡的相关信息和进行对应配置.其中iw.iwconfig和ethtoo ...