Alias Method解决随机类型概率问题(别名算法)

举个例子,游戏中玩家推倒了一个boss,会按如下概率掉落物品:10%掉武器 20%掉饰品 30%掉戒指 40%掉披风。现在要给出下一个掉落的物品类型,或者说一个掉落的随机序列,要求符合上述概率。

一般人会想到的两种解法

第一种算法,构造一个容量为100(或其他)的数组,将其中10个元素填充为类型1(武器),20个元素填充为类型2(饰品)...构造完毕之后,在1到100之间取随机数rand,取到的array[rand]对应的值,即为随机到的类型。这种方法优点是实现简单,构造完成之后生成随机类型的时间复杂度就是O(1),缺点是精度不够高,占用空间大,尤其是在类型很多的时候。

第二种就是一般的离散算法,通过概率分布构造几个点,[10, 30, 60, 100],没错,后面的值就是前面依次累加的概率之和(是不是像斐波那契数列)。在生成1~100的随机数,看它落在哪个区间,比如50在[30,60]之间,就是类型3。在查找时,可以采用线性查找,或效率更高的二分查找,时间复杂度O(logN)。

下面是第二种算法使用二分查找的实现:

<?php
class DiscreteSample
{private $cdf;private $cnt;public function init($pdf){$this->cnt = count($pdf);if($this->cnt == 0)die("pdf size is empty");if(abs(array_sum($pdf) - 1) > 0.00001)die("pdf sum not equal 1, sum:".array_sum($pdf));$this->_pdf2cdf($pdf);}private function _pdf2cdf($pdf){$this->cdf = $pdf;for ($i=1; $i < $this->cnt; $i++){ $this->cdf[$i] += $this->cdf[$i - 1];}//因为浮点型精度问题,最后一个值强制为1$this->cdf[$this->cnt - 1] = 1;}public function next_rand(){$left = 0;$right = $this->cnt;$random = mt_rand() / mt_getrandmax();while ($left < $right - 1) {$mid = intval(($left + $right)/2);if($mid - 1 >= $this->cnt) break;if($random > $this->cdf[$mid - 1])$left = $mid;else$right = $mid;}return $left;}
}
?>

Alias Method(别名方法)

别名算法最终的结果是要构造拼装出一个每一列合都为1的矩形,若每一列最后都要为1,那么要将所有元素都乘以4(概率类型的数量)

此时会有概率大于1的和小于1的,接下来就是构造出某种算法用大于1的补足小于1的,使每种概率最后都为1,注意,这里要遵循一个限制:每列至多是两种概率的组合。

最终,我们得到了两个数组,一个是在下面原始的prob数组[0.4,0.8,0.6,1],另外就是在上面补充的Alias数组,其值代表填充的那一列的序号索引,(如果这一列上不需填充,那么就是NULL),[3,4,4,NULL]。当然,最终的结果可能不止一种,你也可能得到其他结果。

等等,这个问题还没有解决,得到这两个数组之后,随机取其中的一列,比如是第三列,让prob[3]的值与一个随机小数f比较,如果f小于prob[3],那么结果就是3,否则就是Alias[3],即4。

我们可以来简单验证一下,比如随机到第三列的概率是1/4,得到第三列下半部分的概率为1/4*3/5,记得在第一列还有它的一部分,那里的概率为1/4*(1-2/5),两者相加最终的结果还是3/10,符合原来的pdf概率。这种算法初始化较复杂,但生成随机结果的时间复杂度为O(1),是一种性能非常好的算法。

代码示例

<?php
class AliasMethod
{private $length;private $prob_arr;private $alias;public function __construct ($pdf){$this->length = 0;$this->prob_arr = $this->alias = array();$this->_init($pdf);}private function _init($pdf){$this->length = count($pdf);if($this->length == 0)die("pdf is empty");if(array_sum($pdf) != 1.0)die("pdf sum not equal 1, sum:".array_sum($pdf));$small = $large = array();for ($i=0; $i < $this->length; $i++) { $pdf[$i] *= $this->length;if($pdf[$i] < 1.0)$small[] = $i;else$large[] = $i;}while (count($small) != 0 && count($large) != 0) {$s_index = array_shift($small);$l_index = array_shift($large);$this->prob_arr[$s_index] = $pdf[$s_index];$this->alias[$s_index] = $l_index;$pdf[$l_index] -= 1.0 - $pdf[$s_index];if($pdf[$l_index] < 1.0)$small[] = $l_index;else$large[] = $l_index;}while(!empty($small))$this->prob_arr[array_shift($small)] = 1.0;while (!empty($large))$this->prob_arr[array_shift($large)] = 1.0;}public function next_rand(){$column = mt_rand(0, $this->length - 1);return mt_rand() / mt_getrandmax() < $this->prob_arr[$column] ? $column : $this->alias[$column];}
}
?>

 

转载于:https://www.cnblogs.com/mmmzh/p/10140992.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos mysql php tomcat_Linux 安装JDK Tomcat MySQL的教程(使用Mac远程访问)

一 环境阿里云服务器: CentOS 7.4 64位(基于RedHat)本机: macOS High Sierra二 压缩包三 文件传输输入SFTP命令连接 -> 输入实例登录密码sftp root公网IP上传put 本地文件 服务器路径下载get 服务器文件 本地路径四 远程访问输入SSH命令连接 ->输入实例登录密码ssh root公…

Java时间和日期指南

长期以来&#xff0c;正确处理日期&#xff0c;时间&#xff0c;时区&#xff0c;夏时制&#xff0c;and年等一直是我的烦恼。 本文并不是一个全面的指南时域&#xff0c;请参阅日期和时间在Java中 -更详细&#xff0c;但略有下降&#xff0c;ekhem&#xff0c;日期。 它仍然是…

Java项目打war包的方法

最近好忙好忙&#xff0c;整理下心情给大家分享下自己在工作中遇到的一点小技巧&#xff0c;希望给遇到同样麻烦的同学一点帮助。 我们知道Java项目打war包可以在Eclipse和MyEclipse工具中自动打包&#xff0c;就是右键&#xff0c;然后导出war包就可以了&#xff0c;可是我发现…

matlab 的cat函数

cat&#xff1a;用来联结数组 1、用法&#xff1a;C cat(dim, A, B) 按dim来联结A和B两个数组。 C cat(dim, A1, A2, A3, ...) 按dim联结所有输入的数组。 2、举例 acat(3,A,B) 左括号后的3表示构造出的矩阵维数&#xff1b;在新的矩阵中第1、2维就是A和B这两个矩…

charles抓取手机APP,配置正确却抓不到数据

1、确保电脑的防火墙是关闭状态 2、如果还是不行的话&#xff0c;把手机wifi断掉后重新连接 转载于:https://www.cnblogs.com/ding-daisy/p/10141843.html

composer查看当前镜像取消_国内全量镜像大全

# 国内全量镜像大全**配置文件.gitignore **json{"name": "topthink/think","description": "the new thinkphp framework","type": "project","keywords": ["framework","thinkphp&quo…

利用C语言创建和使用DLL文件

有感于讲C语言的DLL文件的文章很少&#xff0c;自己查了半天&#xff0c;写了这么个非常简单的教程。自己也是摸C语言不久&#xff0c;依然感觉处于编程苦手的阶段。1&#xff09;为什么使用DLL文件C语言复用代码有很多的形式&#xff0c;利用动态链接库&#xff08;DLL&#x…

vba判断文件编码格式_如何在VBA判断EXCEL或WORD文件已经打开,并用代码关闭

谢谢寻欢&#xff0c;原来核心就是GETOBJECT&#xff0c;特帖帮助内容&#xff0c;与大家分享&#xff1a;GetObject 函数示例该示例使用 GetObject 函数来获取对指定的 Microsoft Excel 的工作表 (MyXL) 的引用。它使用工作表的 Application 属性来显示或关闭 Microsoft Excel…

spring-service.xml 模板

ssm模板<?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xmlns:context"http://www.springframework.org/…

配置编译win7+VS2017+opencv4.0.1+contrib4.0.1

一、注意 1、opencv个各个版本并不是支持所有的VS版本&#xff0c;如opencv4.0.1支持vc14和vc15&#xff0c;而VS2013是vc12&#xff0c;配置起来会出错。 VS是一个集成开发环境&#xff0c;有不同的版本如VS2013&#xff0c;VS2015; vc是一个c的编译器&#xff0c;也有不同的…

scrapy立面parse_立面设计模式–设计观点

scrapy立面parse在上一篇文章中&#xff0c;我们描述了适配器设计模式 。 在今天的文章中&#xff0c;我们将介绍另一种类似的“四结构帮派”模式 。 顾名思义&#xff0c;结构模式用于从许多不同的对象形成更大的对象结构。 外观模式就是这样一种模式&#xff0c;它为系统内的…

[C++]在Visual Studio 2010中使用Google Test - 配置

我主要是想使用单元测试&#xff0c;VS2010是有自己的单元测试的&#xff0c;虽然我不抵触Microsoft的东西&#xff0c;但是自己做的非工业级的东西&#xff0c;去用Microsoft的解决方案是找罪受~所以使用了Google的测试方案。主要查阅了国外的一篇资料&#xff0c;虽然那位写得…

为什么传值时加号变成了空格_URL的参数中有加号传值变为空格的问题(URL特殊字符)...

1.URL特殊字符需转义2.空格换成加号()3.正斜杠(/)分隔目录和子目录4.问号(?)分隔URL和查询5.百分号(%)制定特殊字符6.#号指定书签7.&号分隔参数转义字符的原因&#xff1a;如果你的表单使用get方法提交&#xff0c;并且提交的参数中有“&”等特殊符的话&#xff0c;如…

LeetCode--single-number复杂度

1、题目 给定一个整数数组&#xff0c;每个元素都出现了两次&#xff0c;但有一个只出现了一次&#xff0c;请找出这个数。 Note&#xff1a;算法要求有线性时间复杂度&#xff0c;并且不占用额外的空间。 2、解法&#xff1a; public class Solution {public int singleNu…

Flask总结

Flask的优缺点 优点&#xff1a;Flask小而精&#xff0c;三方组件全 缺点&#xff1a;稳定性相对较差&#xff0c;三方组件版本问题&#xff0c;Flask一旦迭代&#xff0c;就可能造成三方组件不兼容的问题。 flask三剑客 小儿子 Django flask HTTPRespon…

交流设计

软件设计至关重要。 它是应用程序的基础。 就像一个蓝图&#xff0c;它为来自不同背景的聚会提供了一个通用平台。 它有助于理解&#xff0c;协作和发展。 设计不应仅视为开发的要素。 它不应该只存在于开发人员的头脑中&#xff0c;否则团队将发现它几乎无法增长&#xff0c;…

云顶之弈机器人法爆_LOL云顶之弈机器人出装怎么选

LOL云顶之弈有很多强力英雄&#xff0c;例如机器人正是当中之一。该棋子可以搭配多种阵容&#xff0c;因此装备选择非常重要。那么机器人怎么出装&#xff1f;下面就为大家带来LOL云顶之弈机器人出装推荐。LOL云顶之弈机器人出装怎么选7人口成型8人口上龙女&#xff0c;9人口千…

C/C++图形化编程(1)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 信念是一把无坚不摧的利刃&#xff01…

在VS2010中使用Git【图文】

在之前的一片博客《Windows 下使用Git管理Github项目》中简单介绍了在Windows环境中使用Git管理Github项目&#xff0c;但是是使用命令行来进行操作的&#xff0c;本文将简单介绍下在VS2010中怎样使用Git&#xff0c;并来管理Github上的项目。 准备 安装Git命令行&#xff0c;…

Docker swarm 笔记

防火墙开放端口&#xff1a; TCP port 2377为集群管理通信TCP and UDP port 7946 为节点间通信UDP port 4789 为网络间流量创建attachable network docker network create --driveroverlay --attachable mynet-core 查看网络 docker network ls在manager1上创建swarm集群&#…