抽奖随机算法的技术探讨与C#实现
一、模拟客户需求
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#实现的更多相关文章
- 微信红包中使用的技术:AA收款+随机算法
除夕夜你领到红包了吗?有的说“我领了好几K!”“我领了几W!” 土豪何其多,苦逼也不少!有的说“我出来工作了,没压岁钱了,还要发红包”.那您有去抢微信红包吗?微信群中抢“新年红包”春节爆红.618微信 ...
- 权重随机算法的java实现
一.概述 平时,经常会遇到权重随机算法,从不同权重的N个元素中随机选择一个,并使得总体选择结果是按照权重分布的.如广告投放.负载均衡等. 如有4个元素A.B.C.D,权重分别为1.2.3.4,随机结果 ...
- java实现权重随机算法
权重随机算法在抽奖,资源调度等系统中应用还是比较广泛的,一个简单的按照权重来随机的实现,权重为几个随机对象(分类)的命中的比例,权重设置越高命中越容易,之和可以不等于100: 简单实现代码如下: im ...
- 七雄Q传封包辅助技术探讨回忆贴
前言 网页游戏2013年左右最火的类型最烧钱游戏,当年的我也掉坑了.为了边玩还满足码农精神我奋力的学习如何来做外挂.2013年我工作的第二个年头.多一半…介绍下游戏<七雄Q传>是北京游戏谷 ...
- 权重随机算法Java实现
权重随机算法在抽奖,资源调度等系统中应用还是比较广泛的,一个简单的按照权重来随机的实现,权重为几个随机对象(分类)的命中的比例,权重设置越高命中越容易,之和可以不等于100: 简单实现代码如下: ? ...
- POJ 3318 Matrix Multiplication(随机算法)
题目链接 随机算法使劲水...srand((unsigned)time(0))比srand(NULL)靠谱很多,可能是更加随机. #include <cstdio> #include &l ...
- hdu 4712 (随机算法)
第一次听说随机算法,在给的n组数据间随机取两个组比较,当随机次数达到一定量时,答案就出来了. #include<stdio.h> #include<stdlib.h> #inc ...
- hdu 4712 Hamming Distance ( 随机算法混过了 )
Hamming Distance Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) ...
- HDU4712+随机算法
随机算法 求n个20位的2进制串的MinDist. Dist:两个串的异或结果中1的个数 /* 随机算法 */ #include<algorithm> #include<iostre ...
随机推荐
- iPhone中国移动收不到彩信,联通不用设置都可以,具体设置方法:
打开“设置”. 打开“通用”. 打开“蜂窝移动网络”. 打开“蜂窝数据移动网络”. 在“蜂窝移动数据”一栏中的“APN”处填入“cmnet”. 在“彩信”一栏中的“APN”处填入“cmnet”,“MM ...
- (剑指Offer)面试题32:从1到n整数中1出现的次数
题目: 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,一共出现了5次. 思路: 1.累加法 累加1到n中每个整数 ...
- 如果浏览器自动调用quirks模式打开的话
(从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期 2014-03-21) 则肯定你的html的声明,没有写好. 今天遇到几个,前面莫名其妙的多了个空格(在网页上看源码是多空格,复制到n ...
- spring4 定时任务
一.spring 定时任务 spring 定时任务 ,最好使用quartz 实现.下面我以spring4为例 二.实战(默认) 1.pom配置 <!-- spring time task --& ...
- CANBus Determining Network Baud Rate, Automatic bit-rate detection
http://www.canbushack.com/blog/index.php?title=determining-network-baud-rate Determining Network Bau ...
- HITAG 2 125kHz RFID IC Read-Write 256 bits
Features 256 bits EEPROM memory organized in 8 pages of 32 bits each 32 bits unique factory programm ...
- 【转】网络中的AS自治域
1. 什么是AS自治域? 全球的互联网被分成很多个AS 自治域,每个国家的运营商.机构.甚至公司等都可以申请AS号码,AS号码是有限的,最大数目是65536.各自分配的IP地址被标清楚属于哪个AS号码 ...
- POJ 2309 BST 树状数组基本操作
Description Consider an infinite full binary search tree (see the figure below), the numbers in the ...
- System.Data.SqlClient.SqlError: 备份集中的数据库备份与现有的 'XXX' 数据库不同
System.Data.SqlClient.SqlError: 备份集中的数据库备份与现有的 'XXX' 数据库不同. 1. 删除与要恢复数据库同名的已经存在的数据库:2. 右击“数据库”选择“还原数 ...
- 【Oracle】ORA-00600: [kfgFinalize_2]
环境: OS:OEL5.6 RAC:10.2.0.1.0 [root@rac2 ~]# crs_stat -t Name Type Target Stat ...