百家号不支持代码格式,文章里的代码排版都是乱的。
如果需要拷贝代码,可以去同名的微信公众号。
上篇最后的问题其实是大名鼎鼎的“约瑟夫问题”,也称为“约瑟夫环问题”。
在百度搜索“约瑟夫问题”,竟然有1230万个结果。
约瑟夫问题的总人数和最后留下的人数都是可以变化的。
所以在历史上,还有一些有名的数学题,其实也是约瑟夫问题的变形。
比如17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。
比如“猴子选王问题”、“丢手绢问题”等等。
约瑟夫问题可以用数学方法求解,甚至可以直接推导出公式。
它也经常出现在各种奥数题中。
不过,约瑟夫问题的数学解法有些难度。
我们要介绍的是利用上篇介绍的Python列表类的特性,简单求解约瑟夫问题。
模拟约瑟夫问题
为了简化问题,我们把总人数减少到6个人。
6个人围坐成一圈,从1开始报数。
接下来是解题最重要的一个技巧。
我们把围成一圈坐,改成排成一排坐。
当第一个人报数“1”之后,相当于他从队伍的第1个变成了队伍的最后1个。
第2个人报数“2”之后,他排到了队伍的最后。
第3个人报数“3”之后,他自杀了,相当于从队伍中把他删除了。
第4个人继续报数“1”之后,他排到队伍的最后。
……
依次类推,模拟约瑟夫问题的整个过程就像下面这样
图6:过程模拟
在整个过程中,我们在反复做同样的事情
把n个人排成一行。
按1,2,3报数
报到1和报到2的人,移动到队伍的末尾。
报到3的人从队伍里移除。
约瑟夫问题的Python解法
有了上面的分析过程和结论。
Python程序已经不难写了,所以先直接给出完整的代码。
people = [1,2,3,4,5,6]
num = 1
while len(people)>1:
if num == 3 :
people.pop(0)
num = 1
else :
people.append(people.pop(0))
num = num + 1
print(people)
people = [1,2,3,4,5,6] ,相当于把 n = 6 个人排成一行。
num = 1, 这是一个用来计数的变量,在下面的while循环里,如果 num比3小,就加1,如果num已经数到3了,就重新变成1。
while的循环条件是 len(people) > 1,也就是说列表里元素的个数大于1个就继续循环。当然,如果想留下多个人的话,把 1改成相应的人数就可以了。
while循环里的逻辑也很简单。如果 num == 3,也即报数的数字是3,就把队伍最前面的元素从队伍里移除 people.pop(0),否则就把队伍最前面的元素移到队伍最后面,people.append(people.pop(0))。这些列表函数的用法都是上一篇刚刚介绍过的。
用列表来表示多维数组
在前面的内容里,我们在列表里放入的是单个的数字。相当于数学上的一维数列。
但是在实际的数学问题中,我们碰到更多的是2维或者多维的数组问题。
比如某次考试的成绩,是否也可以存储在列表里?
前面介绍过,列表就像哆啦a梦的魔法口袋,可以装任何东西。所以,也可以用来存储多维的数组。
以保存前5名同学的成绩为例,无非是列表score里面的元素还是列表。
比如score的第1个元素是 [85,100,98],表示的是学号1的同学的语文、数学、英语的成绩。
score = [[85,100,98],[80,100,100],[79,100,100],[86,99,98],[77,98,97]]
假设我们已经把同学们的成绩存储进了列表,怎么从列表里查询需要的成绩呢?
其实和之前介绍的下标,下标切片的方法并没有区别。
要注意的几点是
下标从0开始。score[0]表示第1个元素切片是半闭半开区间。sourc[1:4]只包括 sourc[1], sourc[2], sourc[3],不包括 sourc[4]
另外,最后一行代码需要理解一下。
score[0:4]相当于下图蓝色框,取到了 1~4号同学的成绩。
score[0:4][1:3]相当于下图红色框,取到了2~3号同学的成绩。
帮助老师统计成绩
假设某班有30名同学,而且老师已经把30名同学的语数外成绩录入到了列表score里,你能帮助老师统计出每科的班级平均分,以及三门总分的班级平均分吗?
当然不会真的要你手工录入30名同学的成绩,下面的程序会随机生成每名同学的成绩(成绩都在80~100之间),后面也会介绍,现在你只管使用score列表就可以了。
import random
score = [ random.sample(range(80,100),3) for i in range(30)]