抽奖随机算法的技术探讨与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 ...
随机推荐
- Spring中的设计模式
[Spring中的设计模式] http://www.uml.org.cn/j2ee/201301074.asp [详解设计模式在Spring中的应用] [http://www.geek521.c ...
- Oracle中TO_DATE格式
转自:http://www.cnblogs.com/ajian/archive/2009/03/25/1421063.html TO_DATE格式(以时间:2007-11-02 13:45:25为 ...
- 检查.net代码中占用高内存函数(翻译)
哈哈,昨天没事做,在CodeProject瞎逛,偶然看到这篇文章,居然读得懂,于是就翻译了一下,当练习英语,同时增强对文章的理解,发现再次翻译对于文章的一些细节问题又有更好的理解.下面是翻译内容,虽然 ...
- Android vector标签 PathData 画图超详解
SVG是一种矢量图格式,是Scalable Vector Graphics三个单词的首字母缩写.在xml文件中的标签是<vector>,画出的图形可以像一般的图片资源使用,例子如下: &l ...
- 新浪微博SSO登陆机制
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- Eclipse设置选中高亮显示(包含debug)
如果不高亮显示了:工具栏里有个黄色小笔的图标,点一下就可以了,或者alt+shift+O 设置高亮显示:
- uva331 - Mapping the Swaps
Mapping the Swaps Sorting an array can be done by swapping certain pairs of adjacent entries in the ...
- 标准SAP中的物料类型
DIEN -服务 ERSA -备件 FERT -成品 HALB -半成品 HAWA -贸易商品 HIBE -经营供应 LEER -虚拟件 NLAG -费存储物料 ROH -原材料 VERP -包装 W ...
- C++ Code_TabControl
主题 1. 选项卡控件基础 2. 显示图标的选项卡 3. 选项卡控件高级 4. 5. 属性 选项卡控件基础 1.插入1个对话框,新建1个类 CCDialog1,1 个对话框对应一个 ...
- <<SAP内存计算——HANA>> 书评
<SAP内存计算——HANA>又是一本在地铁里读完的书,最近阅读量大增,都是托了地铁的福了. 一年多以前就在ITPUB里发过帖子问“SAP HANA归根揭底到底是什么?”,那时通过一些网络 ...