python解决约瑟夫问题_17.只能活一个,利用Python列表特性巧妙求解约瑟夫问题

百家号不支持代码格式,文章里的代码排版都是乱的。

如果需要拷贝代码,可以去同名的微信公众号。

f703738da97739129b0470b562f1001e377ae237.jpeg?token=b60a8c1fa4b8bc91a8128f8686d4ea16

上篇最后的问题其实是大名鼎鼎的“约瑟夫问题”,也称为“约瑟夫环问题”。

在百度搜索“约瑟夫问题”,竟然有1230万个结果。

6a600c338744ebf8e00a63784011512c6159a769.jpeg?token=61dc5e9fdebd3df124eb9b563f22bd8d

约瑟夫问题的总人数和最后留下的人数都是可以变化的。

所以在历史上,还有一些有名的数学题,其实也是约瑟夫问题的变形。

比如17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。

比如“猴子选王问题”、“丢手绢问题”等等。

约瑟夫问题可以用数学方法求解,甚至可以直接推导出公式。

它也经常出现在各种奥数题中。

4610b912c8fcc3ce29a2433509ad508ed53f2041.jpeg?token=eb2ff7b0f6f26b0e59f4765deb5bd130

不过,约瑟夫问题的数学解法有些难度。

我们要介绍的是利用上篇介绍的Python列表类的特性,简单求解约瑟夫问题。

模拟约瑟夫问题

为了简化问题,我们把总人数减少到6个人。

6个人围坐成一圈,从1开始报数。

接下来是解题最重要的一个技巧。

我们把围成一圈坐,改成排成一排坐。

00e93901213fb80ed4b7fb29ac39a928bb3894dd.jpeg?token=083bccb51eb0a4f3f99955a603f964aa

当第一个人报数“1”之后,相当于他从队伍的第1个变成了队伍的最后1个。

7e3e6709c93d70cfcbd030cc62345706bba12b3c.jpeg?token=7a5f4c5a998611d32a49847caf3c1a07

第2个人报数“2”之后,他排到了队伍的最后。

d62a6059252dd42a190c36229ad3ddb3c8eab824.jpeg?token=0f193becdde068c3d1d19298f92d5b9e

第3个人报数“3”之后,他自杀了,相当于从队伍中把他删除了。

d53f8794a4c27d1e1ab9e4e3813d2b68dcc4386d.jpeg?token=470ce0daa04cd351c816373ef7876e40

第4个人继续报数“1”之后,他排到队伍的最后。

4a36acaf2edda3cce40d4c8e9801bf07233f92a6.jpeg?token=d422fd2fe87a7a9dd3cd2240a9e54a09

……

依次类推,模拟约瑟夫问题的整个过程就像下面这样

b64543a98226cffc456e0c5320e9cc96f403eafe.jpeg?token=908a761c03387b40c6ad77affff798a1

图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维或者多维的数组问题。

比如某次考试的成绩,是否也可以存储在列表里?

37d3d539b6003af3c76aa94dacc2405a1138b63e.jpeg?token=128833bb125f225e3a1cfa5ec2344225

前面介绍过,列表就像哆啦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]

77c6a7efce1b9d16fc8dc1c16a3632898d546432.jpeg?token=0b256a4f4ebb0a5e6a5e00568a023229

另外,最后一行代码需要理解一下。

score[0:4]相当于下图蓝色框,取到了 1~4号同学的成绩。

score[0:4][1:3]相当于下图红色框,取到了2~3号同学的成绩。

d043ad4bd11373f0af67f8343de7cdfdfaed042b.jpeg?token=164258a54a4df171df3a68ceae416cd0

帮助老师统计成绩

假设某班有30名同学,而且老师已经把30名同学的语数外成绩录入到了列表score里,你能帮助老师统计出每科的班级平均分,以及三门总分的班级平均分吗?

当然不会真的要你手工录入30名同学的成绩,下面的程序会随机生成每名同学的成绩(成绩都在80~100之间),后面也会介绍,现在你只管使用score列表就可以了。

import random

score = [ random.sample(range(80,100),3) for i in range(30)]

574e9258d109b3de95f5aef95457ea87820a4cc3.jpeg?token=874d7b41ed1ed6dcffbf3bff7900d1fb

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值