第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
View Code

第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,是则进行最后一次运输并结束循环

代码运行结果为:
image.jpg
image.jpg

#小思考1

为什么65-88行中不用判断是否与前面过来的船重复呢?

#小思考2

代码中有哪些是可以删除的嘛

posted @ 2022-01-06 18:00  LG03  阅读(232)  评论(0编辑  收藏  举报