https://blog.csdn.net/huyuyang6688/article/details/50480687

如有4个元素A、B、C、D,权重分别为1、2、3、4,随机结果中A:B:C:D的比例要为1:2:3:4。

总体思路:累加每个元素的权重A(1)-B(3)-C(6)-D(10),则4个元素的的权重管辖区间分别为[0,1)、[1,3)、[3,6)、[6,10)。

然后随机出一个[0,10)之间的随机数。落在哪个区间,则该区间之后的元素即为按权重命中的元素。

实现方法:

利用TreeMap,则构造出的一个树为:

B(3)

/      \

/           \

A(1)       D(10)

/

/

C(6)

然后,利用treemap.tailMap().firstKey()即可找到目标元素。

(3落在70%权重,7落在70-95的权重,10落在95-100的权重)

https://www.bbsmax.com/A/LPdo4pk2z3/

三、依赖不可控的物理随机数

什么意思呢,先看个图,看完你就知道了

明白了吧,呵呵,这就是现如今灰常流行的一种抽奖算法,绝对公平、绝对透明、绝对木有暗箱(除非偷偷给你换了抽奖号码)!但是这种方法唯一的缺点是无法实时抽奖,只能事后抽奖。也就是只能拿个抽奖号等着上帝的眷顾,阿门。。。

例如游戏中打败一个boss,会掉落下面其中一个物品,而每个物品都有一定概率: 1. 靴子 20% 2. 披风 25% 3. 饰品 10% 4. 双手剑 5% 5. 金币袋 40% 现在的问题就是如何根据概率掉落一个物品给玩家。

一. 一般算法:生成一个列表,分成几个区间,例如列表长度100,1-20是靴子的区间,21-45是披风的区间等,然后随机从100取出一个数,看落在哪个区间。算法时间复杂度:预处理O(MN),随机数生成O(1),空间复杂度O(MN),其中N代表物品种类,M则由最低概率决定。

二、离散算法:也就是上面的改进,竟然1-20都是靴子,21-45都是披风,那抽象成小于等于20的是靴子,大于20且小于等于45是披风,就变成几个点[20,45,55,60,100],然后也是从1到99随机取一个数R,按顺序在这些点进行比较,知道找到第一个比R大的数的下标,比一般算法减少占用空间,还可以采用二分法找出R,这样,预处理O(N),随机数生成O(logN),空间复杂度O(N)。 请点击查看详细:http://www.cnblogs.com/miloyip/archive/2010/04/21/1717109.html

三、Alias Method Alias Method就不太好理解,实现很巧妙,推荐先看看这篇文章:http://www.keithschwarz.com/darts-dice-coins/ 大致意思:把N种可能性拼装成一个方形(整体),分成N列,每列高度为1且最多两种可能性,可能性抽象为某种颜色,即每列最多有两种颜色,且第n列中必有第n种可能性,这里将第n种可能性称为原色。 想象抛出一个硬币,会落在其中一列,并且是落在列上的一种颜色。这样就得到两个数组:一个记录落在原色的概率是多少,记为Prob数组,另一个记录列上非原色的颜色名称,记为Alias数组,若该列只有原色则记为null。

之前的例子,为了便于演示换成分数

1. 靴子 20% -> 1/4

2. 披风 25% -> 1/5

3. 饰品 10% -> 1/10

4. 双手剑 5% -> 1/20

5. 金币袋 40% -> 2/5

然后每个都乘以5(使每列高度为1),再拼凑成方形

拼凑原则:

每次都从大于等于1的方块分出一小块,与小于1的方块合成高度为1

由上图方形可得到两个数组: Prob: [3/4, 1/4, 1/2, 1/4, 1] Alias: [4, 4, 0, 1, null] (记录非原色的下标)

之后就根据Prob和Alias获取其中一个物品 随机产生一列C,再随机产生一个数R,通过与Prob[C]比较,R较大则返回C,反之返回Alias[C]。

Alias Method 复杂度:预处理O(NlogN),随机数生成O(1),空间复杂度O(2N)

https://www.cnblogs.com/younggun/p/3249772.html

简介

最近闲的无聊,将以前做的一个微信抽奖小demo拿来分享一下,以便加深印象。

效果图

1.gif

业务要求

在一个奖池中放一堆奖品,分别给它们设置不同的数量,比如一等奖A10个,二等奖B,30个,三等奖C10个,然后设置参与人数C人

条件是:

当奖品数大于参与人数,100%中奖。

当奖品A发放完是,不能被抽中。

当奖品发放完毕是,该抽奖活动自动下架。

同一个用户如果中奖了,将不能继续参与该活动。

这里只讨论下其中的核心算法的设计及一个示例函数,算法之外的系统控制暂不提及。

实现抽奖的方法应该有很多,没有仔细去考察和搜索那些非常复杂的算法,这里仅做了一个简单的假设,并在此基础上推出后面所有的控制逻辑。

实现方法

java核心抽奖代码如下:

public classLotteryUtil {/***

*@paramorignalRates 传人每一个奖品概率的集合,(集合的第一个参数是0.0 表示百分比中奖)

*@return

*/

public static int lottery(ListorignalRates) {if (orignalRates == null ||orignalRates.isEmpty()) {return -1;

}int size =orignalRates.size();//计算总概率,这样可以保证不一定总概率是1

double sumRate =0d;for (doublerate : orignalRates) {

sumRate+=rate;

}//计算每个物品在总概率的基础下的概率情况

List sortOrignalRates = new ArrayList(size);

Double tempSumRate=0d;/*遍历奖品概率的集合,计算每一个奖品的中间区间*/

for (doublerate : orignalRates) {

tempSumRate+=rate;

sortOrignalRates.add(tempSumRate/sumRate);

}//根据区块值来获取抽取到的物品索引

double nextDouble =Math.random();

sortOrignalRates.add(nextDouble);

Collections.sort(sortOrignalRates);returnsortOrignalRates.indexOf(nextDouble);

}

}

抽奖的业务逻辑代码如下

/*awardItems获取奖品的一个集合*/

if (activityUserDao.getCountByOpenId(Award.WHEEL_AWARD_TYPE, wid, open_id) <= 0) {/*awardItems获取奖品的一个集合*/List awardItems =awardDao.getByActivity(aw.getWheel_id(), Award.WHEEL_AWARD_TYPE);/*lotterys存放每一个奖品的中奖概率集合*/List lotterys = new ArrayList();/*获取总的奖品数量*/

int count = 0;for(Award a : awardItems) {

count+=a.getProvide_count();

}if (aw.getPeople_count() <=count) {

lotterys.add(0.0); //100%中奖

} else{/*预计参与人数减去奖品数 除以参与人数 = 未中奖概率*/lotterys.add((double) (aw.getPeople_count() - count) / (double) aw.getPeople_count());

}/*遍历奖品集合,获取每一个奖品中奖概率*/

for(Award a : awardItems) {if (a.getOver_count() > 0) {

lotterys.add((double) a.getProvide_count() / (double) aw.getPeople_count());

}else{

lotterys.add(0.0);

}

}//计算中奖概率

int index =LotteryUtil.lottery(lotterys);if (index > 0) {//中奖

Award a = awardItems.get(index - 1);long key = Math.round(Math.random() * (999999 - 100000) + 100000); //6位数中奖序列号//修改商品剩余数量 + 记录序列号

if (awardDao.doLowerOverCount(a.getAward_id()) > 0

&& activityUserDao.doInsert(new ActivityUser(aw.getPublic_id(), Award.WHEEL_AWARD_TYPE, wid, a.getAward_id(), key + "", open_id)) > 0) {

rb.setCode(index);

rb.setData(key);

rb.setMessage(a.getAward_name());

}else{

rb.setCode(0);

}

}//抽奖记录

activityRecordDao.doInsert(new ActivityRecord(open_id, Award.WHEEL_AWARD_TYPE, wid, request.getRemoteAddr()));

前端抽奖工具类

/**

* 注意:本插件运用了rem屏幕适配方案,一律采用rem作为单位,若项目中不是采用这种方案的,此段代码不会影响功能使用,仅会影响控件样式*/(function(win, doc, $) {var defaultOpt ={

rotateNum:5, //转盘转动圈数

body: "", //大转盘整体的选择符或zepto对象

disabledHandler:function() {}, //禁止抽奖时回调

clickCallback:function() {}, //点击抽奖按钮,再次回调中实现访问后台获取抽奖结果,拿到抽奖结果后显示抽奖画面

KinerLotteryHandler:function(deg) {} //抽奖结束回调

};functionKinerLottery(opts) {this.opts = $.extend(true, {}, defaultOpt, opts);this.doing = false;this.init();

}

KinerLottery.prototype.setOpts= function(opts) {this.opts = $.extend(true, {}, defaultOpt, opts);this.init();

};

KinerLottery.prototype.init= function() {var self = this;this.defNum = this.opts.rotateNum * 360; //转盘需要转动的角度

//console.log(this.defNum);

//alert(this.defNum);

//点击抽奖

$('#box').on('click', ".KinerLotteryBtn", function() {if($(this).hasClass('start') && !self.doing) {

self.opts.clickCallback.call(self);

}else{var key = $(this).hasClass('no_start') ? "noStart" : $(this).hasClass('completed') ? "completed" : "illegal";

self.opts.disabledHandler(key);

}

});

$(this.opts.body).find('.KinerLotteryContent').get(0).addEventListener('webkitTransitionEnd', function() {

self.doing= false;var deg = $(self.opts.body).attr('data-deg');if(self.opts.direction == 0) {

$(self.opts.body).attr('data-deg', 360 -deg);

$(self.opts.body).find('.KinerLotteryContent').css({'-webkit-transition': 'none','transition': 'none','-webkit-transform': 'rotate(' + (deg) + 'deg)','transform': 'rotate(' + (deg) + 'deg)'});

self.opts.KinerLotteryHandler(360 -deg);

}else{

$(self.opts.body).attr('data-deg', deg);

$(self.opts.body).find('.KinerLotteryContent').css({'-webkit-transition': 'none','transition': 'none','-webkit-transform': 'rotate(' + (-deg) + 'deg)','transform': 'rotate(' + (-deg) + 'deg)'});

self.opts.KinerLotteryHandler(deg);

}

});

};

KinerLottery.prototype.goKinerLottery= function(_deg) {if(this.doing) {return;

}var deg = _deg + this.defNum;var realDeg = this.opts.direction == 0 ? deg : -deg;this.doing = true;

$(this.opts.body).find('.KinerLotteryBtn').addClass('doing');

$(this.opts.body).find('.KinerLotteryContent').css({'-webkit-transition': 'all 5s','transition': 'all 5s','-webkit-transform': 'rotate(' + (realDeg) + 'deg)','transform': 'rotate(' + (realDeg) + 'deg)'});

$(this.opts.body).attr('data-deg', _deg);

};

win.KinerLottery=KinerLottery;

})(window, document, $);

前端js调用抽奖类

/**

* @author wjb

* @description

* @version 1.0.0 2017/2/11*/app.controller("wheelOneController", ['$scope', '$stateParams', '$neu_', 'awardService', '$filter', '$timeout', 'util.alert', 'cfg', 'wxService', function($scope, $stateParams, $neu_, awardService, $filter, $timeout, alert, cfg, wxService) {/*中奖开始时间*/$scope.wheelStatu={

start:true,

noStart:false,

completed:false}/*错误信息提示*/$scope.errorMsg= "";/*定义奖品数据变量*/$scope.awards=[];/*活动的id和活动的微信公众号ID*/

var activity_id = $neu_.isEmpty($stateParams.activity_id) ? 1: $stateParams.activity_id;var public_id = $neu_.isEmpty($stateParams.public_id) ? 1: $stateParams.public_id;var open_id = $neu_.isEmpty($stateParams.open_id) ?cfg.openId : $stateParams.open_id;

cfg.public_id=public_id;

cfg.open_id=open_id;

cfg.activity_id=activity_id;//alert(cfg.public_id+"=="+cfg.activity_id+"=="+cfg.open_id );

/*获取活动信息*/wxService.setConfig();

awardService.getWheelInfo(activity_id, public_id).then(function(res) {//console.dir(res)

if(res.success) {

$scope.wheelStatu.start= true;

}else{if(res.code == 1 || res.code == 3) {

$scope.wheelStatu.noStart= true;

}else if(res.code == 2) {

$scope.wheelStatu.completed= true;

}

$scope.errorMsg=res.msg;

}

$scope.wheelInfo=res.data;

});

awardService.getAwards(activity_id, public_id).then(function(res) {

$scope.awards=res.data;

});/*奖品预览*/

var result =[];

$scope.showPic= function(pic) {if(result.length == 0) {

$neu_.each($scope.awards,function(item) {

result.push(cfg.resourcePath+item.img);

});

}

wxService.previewImage(cfg.resourcePath+pic, result);

}/*中奖结果集*/$scope.result=[];

$scope.user={

user_name:'',

phone:'',

activity_id: activity_id,

user_openid: open_id

};/**

* 提交中奖人信息*/$scope.submit= function() {

$(".actBody_close").click();

$scope.isLoading= true;

awardService.updateLotteryUser($scope.user).then(function(res) {

$scope.isLoading= false;if(res.success) {

alert('您的中奖信息已备案,我们的客服人员稍后会联系您,如何领取奖品');

}else{

alert('提交失败');

}

})//alert('哈哈上当了吧^_^_^_^')

}

$scope.load= function() {

$timeout(function() {

ActBounced();

$("#layer").hide();newKinerLottery({

rotateNum:5, //转盘转动圈数

body: "#box", //大转盘整体的选择符或zepto对象

direction: 0, //0为顺时针转动,1为逆时针转动

disabledHandler: function(key) {switch(key) {case "noStart":

$scope.$apply(function() {

alert($scope.errorMsg);

});break;case "completed":

$scope.$apply(function() {

alert($scope.errorMsg);

});break;

}

},//禁止抽奖时回调

clickCallback: function() {var this_ = this;//此处访问接口获取奖品

$scope.isLoading = true;

awardService.startAweel(activity_id, open_id).then(function(res) {

$scope.isLoading= false;if(isDebug){

this_.goKinerLottery(0);

}else{if(res.success) {var index = cfg.isDebug ? Math.floor(Math.random() * 5) : res.code;

$scope.result= $filter('awardToAngle')(index, $scope.awards);if(index == 0) {

this_.opts.disabledHandler("noStart");

}else{

this_.goKinerLottery($scope.result[1]);

}

}else{

alert(res.msg);

}

}

})

},//点击抽奖按钮,再次回调中实现访问后台获取抽奖结果,拿到抽奖结果后显示抽奖画面

KinerLotteryHandler: function(deg) {

$("#smallActAdv").click();

}

});

},500);/*分享授权的地址*/$timeout(function(){var share ={shareUrl:"weixin/oauth.html?isBase=true&type=6&a_id="+activity_id+"&p_id="+public_id+"&appid="+cfg.appId};

wxService.onMenuShareAppMessage(share);

},3000)

}

}])

以上是抽奖的主要代码

java 抽奖_JAVA基于权重的抽奖相关推荐

  1. JAVA基于权重的抽奖

    https://blog.csdn.net/huyuyang6688/article/details/50480687 如有4个元素A.B.C.D,权重分别为1.2.3.4,随机结果中A:B:C:D的 ...

  2. 砸金蛋java代码_java实现砸金蛋抽奖功能

    本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下 代码如下 需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%. 累计砸第n次时必抽 ...

  3. 数字识别java开源_Java基于opencv实现图像数字识别(三)—灰度化和二值化

    Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...

  4. socket java 客户端_Java基于socket实现的客户端和服务端通信功能完整实例

    本文实例讲述了Java基于socket实现的客户端和服务端通信功能.分享给大家供大家参考,具体如下: 以下代码参考马士兵的聊天项目,先运行ChatServer.java实现端口监听,然后再运行Chat ...

  5. 抽奖功能java开发_基于Java实现抽奖系统

    摘要:这篇Java开发技术栏目下的"基于Java实现抽奖系统",介绍的技术点是"抽奖系统.Java.抽奖.基于.系统.实现",希望对大家开发技术学习和问题解决有 ...

  6. java 抽奖系统源码_基于jsp的抽奖系统-JavaEE实现抽奖系统 - java项目源码

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的抽奖系统, 该项目可用各类java课程设计大作业中, 抽奖系统的系统架构分为前后台两部分, 最终实现在线上进行抽奖 ...

  7. java抽奖_Java实现抽奖功能

    需求简介 新项目有一个类似王者荣耀抽奖的功能:抽取花费积分,积累幸运值,每阶段幸运值可以抽取到不同的奖品,幸运值集满时,必得稀有道具 功能实现预期:建立一个抽奖池(抽奖池级别根据type区分),奖品在 ...

  8. java用map集合实现随机抽奖源码

    import java.util.HashMap; import java.util.Random;//用map实现抽奖 public class demo3 {public static void ...

  9. 基于vue2.0+ 抽奖项目

    前言 临近年关抽奖活动,基于vue2.0+开发的抽奖项目. 便于查看效果,贴上相关地址: 在线示例地址:快速访问 github地址:查看源码 简介 基于vue.js抽奖项目,截屏保存每次抽奖图片至本地 ...

最新文章

  1. 有关Expander组件的研究——Silverlight学习笔记[33]
  2. Invalid icon file 原因
  3. Tensorflow官方文档中文版——第一章
  4. 【2017-04--28】Winform中ListView控件
  5. 云原生,开发者的黄金时代
  6. 两个有序数组的中位数—leetcode4
  7. oracle 数据操作的相关参数
  8. React v16版本 源码解读
  9. 突然不能访问服务器未响应,windows 访问不服务器未响应
  10. C语言中的字符串函数
  11. php dede 发布时间_DedeCMS发布时间显示多少天月年前
  12. abaqus结构工程分析及实例详解pdf_“结构非线性、材料拟合、冲击碰撞、钣金/金属成形、顺序耦合、多物理场、有/非参优化”专题...
  13. 第一次在CSDN上写博客
  14. Python基于HRHet的跌倒检测系统(源码&教程)
  15. 基于Transformer的NLP智能对话机器人实战课程(第十六章、第十七章、第十八章)
  16. 关于百度OCR和EasyOCR的研究记录
  17. html5弹页面腮红,腮红总是打的很奇怪 这里有画腮红的小技巧
  18. 【Oracle】userenv()函数介绍分析
  19. oracle sql 不等 优化6,oracle sql 优化(三)
  20. 哲学家就餐问题python解决_关于哲学家就餐问题的分析代码.

热门文章

  1. 计算机文档排版软件,正式文档排版格式计算机软件及应用IT计算机专业资料-正式文档排.pdf...
  2. 广告、广告联盟、异业联盟及广告接入介绍
  3. GCJ经纬度(腾讯、高德)转WGS84经纬度EXCEL算法
  4. 统计力学练习: Ising模型的平均场解以及严格求解
  5. 捕捉RAISERROR异常
  6. 计算机的优缺点英语作文100词,跪求一篇英语作文 题目:论计算机的优缺点
  7. 996 有加班费,那加班是否合算?
  8. Vmware Ubuntu虚拟机之间传文件,Ubuntu ftp的相关设置
  9. nbtscan局域网内查找病毒主机
  10. 有声书制作是什么?有声书和电子书的区别是什么?