# 第50期-八人过河
Python是一门需要不断实践练习的编程语言,本文档将AI大学堂学员交流群的Python每周练习进行汇总,希望各位小伙伴能够多进行实践练习,逐渐爱上这门神奇的编程语言,掌握它并在生活中能够使用它。
# 1 问题描述
现在有8个人分别为:1个父亲,带着他的2个儿子。1个母亲,带着她的2个女儿;1个警察,带着1个犯人;
开始时,8个人都是在河的左岸。现在需要过河,过河时需要注意下面5条说明:
1,只有警察、父亲和母亲可以划船;
2,警察如果离开犯人,犯人就会伤害其他人;
3,母亲不在时,这个父亲会伤害她的女儿。
4,父亲不在时,这个母亲也会伤害他的儿子;
5,船上一次最多只能坐两个人。
试用python求出过河方案。
# 2 解题思路
- 第一步: 首先需要创建函数排除所有不能出现的情况
- 第二步: 遍历所有过河的可能
- 第三步: 通过第一步与第二部结合排除大部分情况
- 第四步: 可能会出现两个人往返过河无限循环的情况,需要排除这种情况
# 3 解题方法
left,ship,right,ship2=['警察','犯人','父亲','儿子','儿子','母亲','女儿','女儿'],[],[],[]
i=j=t=0
def rules(left1,right1,ship1):
x=[left1,right1,ship1]
for i in x:
if ('父亲' not in i) and ('母亲' in i) and ('儿子' in i) :
assert False
if ('母亲' not in i) and ('父亲' in i) and ('女儿' in i) :
assert False
if ('警察' not in i) and ('犯人' in i) and (len(i)!=1):
assert False
if (i==ship1):
if '父亲' not in i and '母亲' not in i and '警察' not in i:
assert False
def actions_1(ship1,right1,left1):
global ship,right,left,i,j,ship2
while True:
left1=left[:]
ship1=ship[:]
right1=right[:]
ship1.append(left1.pop(i))
ship1.append(left1.pop(j))
for k in ship1:
right1.append(k)
try:
rules(left1,right1,ship1)
if sorted(ship1)==sorted(ship2):
assert False
break
except:
j=j+1
if j>len(left1):
i=i+1
j=i
if i == len(left1)+1:
break
ship2=ship1
ship=[]
right=right1
left=left1
i=j=0
def actions_2(ship1,right1,left1):
global ship,right,left,i,j,t,ship2
while True:
left1=left[:]
ship1=ship[:]
right1=right[:]
ship1.append(right1.pop(t))
for k in ship1:
left1.append(k)
try:
rules(left1,right1,ship1)
break
except:
t=t+1
if t == len(right1)+1:
left1=left[:]
ship1=ship[:]
right1=right[:]
break
if ship1==[]:
while True:
left1=left[:]
ship1=ship[:]
right1=right[:]
ship1.append(right1.pop(i))
ship1.append(right1.pop(j))
for k in ship1:
left1.append(k)
try:
rules(left1,right1,ship1)
break
except:
j=j+1
if j>len(right1):
i=i+1
j=i
if i == len(right1)+1:
break
ship2=ship1
ship=[]
right=right1
left=left1
i=j=t=0
while True:
actions_1(ship,right,left)
print(f'{ship2}从左往右')
print(f'此时左边剩下{left},右边剩下{right}')
actions_2(ship,right,left)
print(f'{ship2}从右往左')
print(f'此时左边剩下{left},右边剩下{right}')
if len(left)==2:
actions_1(ship,right,left)
print(f'{ship2}从左往右')
print(f'此时左边剩下{left},右边剩下{right}')
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
第1行: 定义列表left、ship、right、ship2并分别添加元素(ship与ship2用来判断是否出现重复循环)
第2行: 定义变量i、j、k用来判断何时结束循环
第5行: 定义规则函数rules并引入自变量left1,right1,ship1
第6行: 为left1,right1,ship1创建列表x
第7-16行: 根据题意创建规则,若违反规则则报错,用于与后面try、except语句相互配合
第18-19行: 创建函数actions_1并引入全局变量ship,right,left,i,j,ship2,代表船从左到右
第20行: 无限循环直到不触碰规则
第21-23行: 复制列表left、ship、right到left1,right1,ship1中
第24-25行: 从左边(left1列表中)选出两个元素移到ship1中
第26-27行: 使用for循环遍历ship1中的元素移到右边(right1列表中)(不删除船中的元素,用以判断本次运行过程是否触发规则)
第28-29行: 判断左岸、船上、右岸的人员是否都会安全,不安全则报错
第30-31行: 判断从右到左的船上和从左到右的船上两人是一样的,若是一样的会陷入循环,报错
第32行: 若都不报错,则行动正确,结束循环
第33行: 若try中报错,则运行此处
第34-37行: 索引i、j进行变化以便下次索引
第38-39行: 超出列表则结束循环(若代码正确这段可以不要)
第40-41行: ship2记住本次行动人员以便下次判断是否重复,ship船清零
第42-43行: 左右两岸记住本次剩余人员
第44行: i、j清零用于下次索引
第46-47行: 创建函数actions_2并引入全局变量ship,right,left,i,j,t,ship2,代表船从右到左
第48行: 无限循环直到不触碰规则
第49-51行: 复制列表left、ship、right到left1,right1,ship1中
第52行: 从右边(right1列表中)选出一个元素移到ship1中(优先选出一个,用于求解)
第53-54行: 使用for循环遍历ship1中的元素移到左边(left1列表中)(不删除船中的元素,用以判断本次运行过程是否触发规则)
第55-56行: 判断左岸、船上、右岸的人员是否都会安全,不安全则报错
第57行: 结束循环(这里一个人和两个人不可能重复,不用判断是否与上次船相等)
第58行: 若try中报错,则运行此处
第59行: 索引t进行变化以便下次索引
第60-64行: 超出列表则结束循环并给left1,right1,ship1重新复制
第65-88行: 参考20-44行,代码基本相同,表示从右边运输两个人到左边
第89行: 无限循环直到运输完毕
第90-95行: 引用左右船两个函数并输出左岸的人数,以及船上的人
第96-100行: 由于最后一段是从左岸到右岸,判断左岸人数是否为2,是则进行最后一次运输并结束循环
代码运行结果为:
# 小思考1
为什么65-88行中不用判断是否与前面过来的船重复呢?
# 小思考2
代码中有哪些是可以删除的嘛?
# 4 视频解析
高清视频讲解,请查看AI大学堂Python基础实战100例 (opens new window)
关注『讯飞AI大学堂』公众号,发送 python100 即可领取Python基础实战100例源代码