一道数学题的思考
Posted Vicent_9920
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一道数学题的思考相关的知识,希望对你有一定的参考价值。
最近看见一道数学题,比较有意思:
房间里有100个人,每人都有100元钱,他们在玩一个游戏。每轮游戏中,每个人都要拿出一元钱随机给另一个人,最后这100个人的财富分布是怎样的?我们不妨把这场游戏视作社会财富分配的简化模型,从而模拟这个世界的运行规律。我们假设:每个人在18岁带着100元的初始资金开始玩游戏,每天玩一次,一直玩到65岁退休。“每天拿出一元钱”可理解为基本的日常消费,“获得财富的概率随机”是为了……嗯……简化模型。以此计算,人一生要玩17000次游戏,即获得17000次财富分配的机会。答案有如下三种情况:
当看见这道题的时候,我认为财富的分布应该是接近均匀分布,毕竟概率是均等的。但是答案竟然是接近冥律分布,为什么呢?我决定使用代码来计算一遍!
使用代码计算,首先考虑一个问题,就是随机数,目前 Random 函数的随机数存在“伪随机”,就是每次的随机数都是一样的,我们可以通过代码来测试一下:
import java.util.Random;
public class MyClass
public static void main(String[] args)
for (int i = 0; i < 3; i++)
System.out.println( "第"+i+"次输出结果"+new Random(5).nextInt(100));
接下来看看日志结果,大家就明白了!
第0次输出结果87
第1次输出结果87
第2次输出结果87
第3次输出结果87
第4次输出结果87
第5次输出结果87
第6次输出结果87
第7次输出结果87
第8次输出结果87
第9次输出结果87
避免随机数的方法比较多,有减掉种子参数()、将 Random 对象生成一个对象,每次使用同一个对象,代码验证一下:
import java.util.Random;
public class MyClass
public static void main(String[] args)
Random rl = new Random();
for (int i = 0; i < 10; i++)
System.out.println( "无种子参数第"+i+"次输出结果"+ new Random().nextInt(10));
System.out.println( "同 Random 对象第"+i+"次输出结果"+ rl.nextInt(10));
日志验证结果:
无种子参数第0次输出结果4
同 Random 对象第0次输出结果6
无种子参数第1次输出结果0
同 Random 对象第1次输出结果1
无种子参数第2次输出结果8
同 Random 对象第2次输出结果8
无种子参数第3次输出结果4
同 Random 对象第3次输出结果4
无种子参数第4次输出结果1
同 Random 对象第4次输出结果8
无种子参数第5次输出结果7
同 Random 对象第5次输出结果6
无种子参数第6次输出结果8
同 Random 对象第6次输出结果4
无种子参数第7次输出结果8
同 Random 对象第7次输出结果2
无种子参数第8次输出结果7
同 Random 对象第8次输出结果8
无种子参数第9次输出结果0
同 Random 对象第9次输出结果1
上述的“伪函数”的原因是种子参数的使用——
在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。因此,相同种子数的Random对象,相同次数生成的随机数字是完全相同的。
了解了Random对象以后,接下来需要实现财富分配的过程,上面说的是规则不大清晰,只说了每个人的初始资金为100元,每次中奖了就分配,然后总次数为17000次。我们在实现的过程中需要考虑的问题还有几点:
- for 循环的时候,是 100 个人每次抽奖 17000 次,还是抽 17000 次奖,每次遍历 100 个人?
- 当每个人的资金减少到0元以后是否还有机会中奖?
- 当有人的资金减少为 0 时,可分配的奖金响应减少,如何纪录?
- 当问题 1 为否定时,会发生无人中奖的情况,这个时候已经出资1元的资金需要取回,且总次数是否增加?
第一、虽然总的计算次数都是1700000次,但是这里的逻辑不一样,前者抽奖次数达到了1700000次,后者抽奖次数固定为17000次,按照逻辑判断,应该选后者。
第二、我将这个问题理解为博弈,并非作者所提的社会问题(社会问题需要考虑到财富平均的财富再分配,博弈考虑的是我付出了有多大的收益),因此第一个问题我的答案是没有机会中奖,这样也会更加公平!
第三、我的做法是在每轮博弈前设置一个奖金初始值 bonus,假设每次一开始都不知道有人需要退出,因此初始值一直是100元,接下来在每次收取博弈奖金的时候判断参与者是否还有资金(资金是否为 0 或者为 -1)参与本轮博弈,没有的话我会给他们一个标记(资金设为 -1),并且将奖金 bonus 减去 1 。当 100 人循环完毕以后,博弈奖金就是 bonus 了!
第四、该问题类似第二个问题,在每轮博弈前设置一个标记 isBouns ,定义为无人中奖。然后在得到 bonus 以后,就可以开奖了。如果遇到无人中奖(假设中奖号为 99 ,但是 99 号没有投注博弈资金了,则本轮无人中奖),这个时候可以通过判断 isBouns 来决定总次数是否增加。由于总次数 17000 次是来自时间的计算,所以这里我也没有增加总次数了。如果需要增加,我们可以对总次数定义一个变量 22K (可以自行百度22k 这个故事),初始值为 17000 ,在无人中奖的时候加 1 即可。
代码如下:
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by κ?? on 2017/7/30.
*/
public class Test
static List<Integer> data = new ArrayList<>();
public static void main(String []args)
Random rl = new Random();
int count = 100;
int all = 17000;
for (int i = 0; i < 100; i++)
data.add(100);
int ran = rl.nextInt(100);
for (int i = 0; i < 17000; i++)
boolean isBouns = false;
int bonus = 100;
for (int j = 0; j < 100; j++)
if(data.get(j) == 0)
data.set(j,-1);
bonus--;
else if(data.get(j) != -1)
int value = data.get(j);
data.set(j,value-1);
else
bonus--;
if(data.get(ran)!=-1)
int value = data.get(ran);
data.set(ran,value+bonus);
isBouns = true;
ran = rl.nextInt(100);
if(!isBouns)
for (int j = 0; j < 100; j++)
int value = data.get(j);
if(value!=-1)
data.set(j,value+1);
System.out.println(getData());
//数据详情
System.out.println(new Gson().toJson(data));
private static int getData()
int result = 0;
int count = 0;
int winer = 0;
for (int i = 0; i < 100; i++)
if(data.get(i) != -1 && data.get(i) != 0)
result+=data.get(i);
count++;
//绝对赢家
if(data.get(i)>100)
winer++;
System.out.println("共有"+winer+"人赢了!其中有"+count+"还有钱!");
//总资金 10000,检查这个值计算是否有计算出错
return result;
最后说一下我的计算结果:
代码运行10 次,累计208人还有钱,其中7人不足100元,也就是说平均每轮(几十年的概念)有20.8%的概率还有能力继续博弈,每轮有20.1%的概率盈利!
参考文章:
http://blog.csdn.net/hla199106/article/details/45030041
文章来源
https://media.weibo.cn/article?id=2309404134038146271148&from=timeline&jumpfrom=weibocom
以上是关于一道数学题的思考的主要内容,如果未能解决你的问题,请参考以下文章
由一道考研基础题引发的关于对(函数导数符号在内外的区别)f‘(x)和[f(x)]‘的区别思考