简评:反直觉的问题,房间内每个人随机给于别人 1 元,你猜不到最后会发生什么。
--- Update ---
知友 KetoneHu 根据本文也写了一篇相关的回答,推荐给大家:从热力学看这个问题
「这个体系用一句热力学的语言来描述的话是:对于一个孤立系统,有恒定数量的粒子和能量(对应人和金钱),这些能量是怎么在粒子之间分布的?」
--- 原文 ---
前几天我们再参加一个电气工程与计算机科学的主题会议,遇到了 Uri Wilensky,他和我们分享了一个很有趣的分配模拟。
问题是这样的:
想象着,有一个房间,里面有 100 个人,每个人有 100 美元。每过一会,每个有钱的人给随机的其他人 1 美元,经过一段时间后,房间内的资金分配情况是怎样?
如果,你快速的思考,然后认为「或多或少的趋于平均」,你这个想法并不孤单。
我问了 5 个超级聪明的博士,他们也都有同样的第一感觉,认为会趋于平均。
所以,真实的分布状况应该是如何呢,请看下面这个 gif。
- gif 的左上角是次数,每次代表着一次财富的改变。
- Y 轴显示的是美元存量,初始 45 美元。
- X 轴显示的是 45 个人。
- 上图(红色图)显示每时,每人的财富。
- 下图(蓝色图)就是把红色图递增排序了一下,方便查看。
不信这个结果么?你可以用 R、tidvverse 和 gganimate 代码自己跑一跑。
不平等可能源于完全无害的政策和规则,你要时刻关注他们。
library(tidyverse)
library(gganimate)
NUMPLAYERS = 45
ROUNDS = 5000
INITWEALTH = 45
#initialize the bank
#columns wealths of the NUMPLAYERS players
#rows show wealths of each of the ROUNDS ticks of the clocks
bank = matrix(0, nrow = ROUNDS, ncol = NUMPLAYERS)
bank[1,] = c(rep(INITWEALTH, NUMPLAYERS))
#function to give a dollar to someone other than oneself
get_recipient = function(player) {
sample(setdiff(1:NUMPLAYERS, player), 1)}
#execute trades and update the ledger
for (i in 2:ROUNDS) {
#every player with wealth chooses another person to receive a buck
recipients = sapply(which(bank[i - 1,] > 0), get_recipient)
#table of the dollars owed each person
count_table = table(recipients)
#get the indices of the people owed money
indices = as.integer(names(count_table))
#everyone gives up a dollar, unless they are at zero
bank[i,] = ifelse(bank[i - 1,] > 0, bank[i - 1,] - 1, bank[i - 1,])
#selected people receive dollars
bank[i, indices] = bank[i, indices] + count_table
}
####################Animate it
#Make a suitable long data frame
df = as.data.frame(bank)
names(df) = 1:NUMPLAYERS
df = df %>%
mutate(frame = 1:ROUNDS) %>%
gather(person, wealth, 1:NUMPLAYERS) %>%
mutate(person = as.numeric(person)) %>%
arrange(frame) %>%
group_by(frame) %>%
mutate(rank = rank(wealth, ties.method = "random")) %>%
ungroup() %>%
gather(histtype,playerid,c(person,rank)) %>%
mutate(histtype = sprintf("Ordered by %s", histtype))
p <- ggplot(df, aes(x = playerid, y = wealth, frame = frame, fill=histtype)) +
theme_minimal() +
theme(panel.grid.major.x = element_blank(),
panel.grid.minor = element_blank()) +
geom_rect(aes( xmin = playerid - .4, xmax = playerid +.4, ymin = 0, ymax = wealth)) +
scale_x_continuous(breaks = 1:NUMPLAYERS) +
coord_cartesian(xlim = c(0, NUMPLAYERS), y = c(0, 5 * INITWEALTH)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
labs(x='players',y='dollars') +
facet_wrap( ~ histtype,ncol=1) +
theme(legend.position = "none")
p
#set options for the animation package. Need ImageMagick installed on your computer
animation::ani.options(nmax = ROUNDS,
convert = 'C:\\Program Files\\ImageMagick-7.0.6-Q16')
#save the movie
gganimate(p, "dollar_stacked.mp4", interval = .01)
(R 语言版,Github:give_a_dollar.R)
园长:我想,这就是运气吧。