基督徒问题的三种python实现方式

问题:

有15个基督徒和15个非基督徒在海上遇险,为了能让一部分人活下来不得不将其中15个人扔到海里面去。

有个人想了个办法就是大家围成一个圈,由某个人开始从1报数,报到9的人就扔到海里面,他后面的人接着从1开始报数,报到9的人继续扔到海里面,直到扔掉15个人。

由于上帝的保佑,15个基督徒都幸免于难,问这些人最开始是怎么站的,哪些位置是基督徒哪些位置是非基督徒。

 

方案一:位置标记

思路:

由于需要标记哪些位置是非基督徒(被扔海里的人),所以30个人的位置不能变,被扔海里的人的位置还需要留着。

所以用people来轮询报数的人的位置,由于是个圈,所以超过30之后要取余数。

用'1'表示活着,用'0'表示丢海里死掉了,是个空位置。

所以刚开始的时候有30个'1'。

然后每次数到9,就把'1'变成'0',报数的时候先判断那个位置上有没有人(是‘1’还是‘0’),没人(‘0’)就跳过。

 

people_list = list('1'*30) # 用1表示活着
people = 0 # 位置索引
dead = 0   # 统计死掉的人
count = 1  # 报数
while dead < 15:
	people = people % 30  # 围成一个圈,所以30个人不停循环
	if people_list[people] == '1': 		# 如果这个人还没死
		if count == 9:					  # 如果他报了9
			people_list[people] = '0'     # 那他就死了
			dead = dead + 1               # 死掉的人+1
			count = 1 					  # 重新报数
		else:							# 如果不是报的9
			count = count + 1 			  # 下一个人报数+1
	people = people + 1 				# 下一个人继续

print(people_list)

结果:

类似的思路也可以用来解决灯开关的问题:

有100盏灯,初始状态为关闭,全由拉绳开关控制。
第一次:被3整除的灯拉一次开关。
第二次:被5整除的灯拉一次开关。
第三次:被7整除的灯拉一次开关 。
最后有几盏灯亮,分别是哪几盏灯?

deng = list('开'*100)

def on_down(i):
	global deng
	if deng[i] == '开':
		deng[i] = '关'
	else:
		deng[i] = '开'

for i in range(100):
	if (i+1)%3 ==0:
		on_down(i)
	if (i+1)%5 ==0:
		on_down(i)
	if (i+1)%7 ==0:
		on_down(i)

print(deng)

 

 

 

 

方案二:重新组队

双向队列可以同时在左右两边进行增加和删除,每次把队列左边的8个人拿出来放到队列右边,这时候最左边的人就是报数9的人,毫不犹豫地杀掉,然后继续从左边取8个人放到队列右边,重复15次就完事了。

import collections

q = collections.deque([i for i in range(1, 31)]) # 从1到30的队列

for _ in range(15):    # 重复15次,杀掉15个人
    for _ in range(8):  # 每次拿出8个人
        q.append(q.popleft())  # 把这8个人从左边放到右边
    q.popleft()  # 拿完8个人就杀掉最左边的人(第9个人)

print(q)

结果:

 

其实用列表也可以更简单地实现:

lists = [i for i in range(1, 31)]
for i in range(15):
	lists = lists[9:] + lists[:8]  # 第9个人之后的队伍和前8个人重新组成数组
print(lists)

结果:

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值