第50期-八人过河
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
第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
代码中有哪些是可以删除的嘛