发表于 2022-4-13 06:32:56 | 2022-4-13 10:11编辑 | 显示全部楼层
近日论坛解谜游戏多了猜数字,出于求知的目的,花了一点时间(大部分时间打游戏去了)考虑了一下猜数字的解法,基于程序设计来探求解法的可行性以及在x次内猜出数字的数学期望。写在前面,本贴所有内容和结论仅供交流学习,不建议通过本贴内容作弊,关于代码的一部分内容我也会封在另一个文件里避免有人用来进行作弊。

一·算法设计
由于在考虑算法的时候,我点开了中阶的猜数字,进不了其他阶的猜数字,所以本贴的解法以中阶的规则为基础。等到有空了会考虑设计一下高阶的解法。
托中阶的福,没有重复数字,因此所有数字都是完全等价的,我们只需要将 5040 种可能的数字看作一个解的集合,通过一次次地猜测来缩小这个解集,最后可以把解集锁定在一个,那么这个解就是答案的数字。
猜数字的结果一共有 (0,0),(0,1),(0,2),(0,3),(0,4),(1,0),(1,1),(1,2),(1,3),(2,0),(2,1),(2,2),(3,0),(4,0) 14 种可能,要判断猜哪个数可以将解集缩到最小,只需要遍历 5040 个可能,将每个可能所对应的 14 种可能结果所得到的缩小解集大小加权求和,即最后的解集期望。我们只需要挑选其中解空间最小的一个,就是我们下一个要猜的数字。


二·代码实现
本人基于 python 实现该功能。
首先需要解决的是输入一个猜的数字,通过与答案的计算得到 xAxB 的结果。
A是数字和位置都正确,那么我们只需要把两个数字看作向量,向量相减后求结果为 0 的维数即可。
B是数字正确位置不正确,万幸没有重复数字,只需要把两个数字看作集合,求出交集大小即为正确的数字个数,减去A就是B了

然后需要一个函数得出最能缩小解空间的解,按照算法设计中的步骤操作即可。这里按理说应该每次都遍历完整的 5040 种可能,但是由于我需要多次计算来得到统计结果,所以擅自将遍历的范围缩小到解空间内,不知道是否会对计算的最坏情况下最少次数产生影响,在严格意义下该代码非最优解法。

同时需要一个函数帮助缩小解空间,只需要遍历解空间,将 xAxB 与结果不符的剔除即可

最后再加点细节以实现一个从生成随机数,记录猜数过程到输出猜数结果的最终猜数函数

将猜数函数循环调用以得到统计学结论

三·问题与优化
由于第一次猜数时需要在全集内进行遍历,较为消耗时间,考虑到猜数结果的可能较少,以及第一次猜数时所有数等价,我固定第一次猜的数为 0123 ,将所有结果对应的最优缩小数以及所对应的缩小后的解空间打表,省去了第一次猜数计算的时间,大大降低了时间复杂度。
将猜数的范围限制在解空间内是一个潜在的隐患,是否存在影响仍需要严格的数学证明,可惜我懒

优化后的最终代码部分见附图

四·统计结果
其实我本来跑了两千多组数据,但是跑完了发现加权的部分写了一点点Bug,天亮了又来不及重跑,只能草草跑 1000 组意思一下。考虑到猜数字次数的结果基本小于10,1000次应该能得到一定意义的统计学结果。

猜数次数 1 2 3 4 5 6 7
出现次数 0 4 20 118 416 385 57


期望约为 5.329 次,方差约为 0.739,最大值为 7 次

测试结果见附件

五·总结
实际上只需要遍历整个解空间的 5040 组数据就可以得到完整的解情况,但是我懒得跑了,随便随机跑了1000组统计一下看看结果。
从结果上看该算法平均需要 5 次左右得出正确的数字,且大部分的次数分布集中在期望附近,边缘的次数分布较少。即使在最坏情况下也只需要猜测 7 次即可得出正确数字(未数学证明)。

高阶的数字组合存在重复数字,解空间大了一个数量级,同时由于重复数字的存在 xAxB 的计算方式也需要重新设计,凌晨写了一下下还是放弃了,有空再继续写。

——————————————————————————————————————————————————————————————
补充:
花了几个小时把 5040 种跑完了,出现了两个 8 次猜测,目前不知道是重视缩小期望而忽略极值的原因还是因为为了缩小时间而把猜的范围限制在解空间的原因。
结果如下
猜数次数 1 2 3 4 5 6 7 8
出现次数 1 13 108 638 2061 1925 292 2

期望为 5.321 方差为 0.577
期望和方差都更小了
本帖子中包含更多图片或附件资源

您需要 登录 才可以下载或查看,没有帐号?加入学院

登录帐号可查看完整回帖内容
| 发表于 2022-4-13 07:46:34 | 发自安卓客户端 | 显示全部楼层
看不懂,但是赞一个!
| 发表于 2022-4-13 07:50:49 | 发自安卓客户端 | 显示全部楼层 发帖际遇
不明觉厉!
| 发表于 2022-4-13 08:08:02 | 显示全部楼层
感谢大佬分析
| 发表于 2022-4-13 08:59:29 | 显示全部楼层
感觉好厉害!
1 | 发表于 2022-4-13 10:33:19 | 显示全部楼层 发帖际遇
也就是说,中阶很大可能是可以100%的。初高阶可以把每个数字加到四个,或者先确定有几个重复数字,或者还有什么更好的方法。
登录帐号可查看完整回帖内容
1 | 发表于 2022-4-13 10:42:19 | 显示全部楼层
@哈士奇
登录帐号可查看完整回帖内容
| 发表于 2022-4-13 10:53:02 | 发自安卓客户端 | 显示全部楼层
大佬游戏打完了
登录帐号可查看完整回帖内容
| 发表于 2022-4-16 18:26:38 | 发自安卓客户端 | 显示全部楼层
好帖我顶
| 发表于 2022-4-18 02:03:01 | 发自安卓客户端 | 显示全部楼层
大佬!我刚学Python不久,现在想用Python实现猜数字游戏。没有英镑只能自己搞着玩了
登录帐号可查看完整回帖内容
返回版块
123
尚未登录
您需要登录后才可以回帖 登录 | 加入学院