传教士与食人者问题python

问题描述

在河的左岸有3个传教士、1条船和3个食人者,传教士们想用这条船将所有的成员运到河的右岸,但是受到以下条件的限制:
(1)船每次最多只能装2个乘客(传教士和食人者都会划船)。
(2)在任何岸边,如果食人者数目超过传教士则传教士将被食人者吃掉。
(3)假定食人者会服从任何一种过河安排。编写深度优先搜索算法程序,找出一个确保全部成员安全过河的解。

思路分析

采用列表status= []# 表示方式[ML, CL, MR, CR, B](左传教士、左食人者、右传教士、右食人者、船)来记录一次操作后的状态,参考魏宇轩大佬的思路,(链接https://kangyanfeng.blog.csdn.net/article/details/84404168)每次操作只有五种可能即0,1 1,0 2,0 0,2 1,1五种动作,也用列表去存储,这样每次的操作就可以用列表元素相加减。而状态点使用字典存放,但是列表不能作为python的键值,所以转化成元组放进字典。之后的算法思路也和魏宇轩大佬的思路相同,但是使用python实现。

代码

g = {}  # 存放父子节点
statusl = []# 表示方式[ML, CL, MR, CR, B]  左传教士、左野人、右传教士、右野人、船
route = []  # 一次路径
way = []  # 总路径
actions = [[1, 0], [0, 1], [1, 1], [0, 2], [2, 0]]  #五种操作方式

def result(s):
    if s[0] < 0 or s[1] < 0 or s[2] < 0 or s[3] < 0:  # 负数
        return
    if (s[0] < s[1] and s[0] != 0) or (s[2] < s[3] and s[2] != 0):  # 传教士被吃
        return
    d = tuple(s)    #元组作为状态点
    if len(statusl) > 1:
        f = tuple(statusl[-2][:])
        if f in g.keys() and d not in g[f]:
            g[f].append(d)
        else:
            g[f] = [d]

    for k in statusl[:-1]:   #重复状态
        if k[0] == s[0] and k[1] == s[1] and k[3] == s[3] and k[4] == s[4]:
            return

    mid = [0] * 5
    for j in actions:
        mid[0] = s[0] - j[0] * s[4]
        mid[1] = s[1] - j[1] * s[4]
        mid[2] = s[2] + j[0] * s[4]
        mid[3] = s[3] + j[1] * s[4]
        mid[4] = -s[4]
        statusl.append(mid[:])
        result(mid)   #判断该动作是否合理,并加入字典
        statusl.pop()
    return


# 深度搜索寻找路径
def dfs(s):
    s = tuple(s)     #字典的值是列表里面包含元组,原因是字典的键值不能是列表
    if s in route:   #已经在路径里面
        route.append(s)
        return
    # 到达终点,记录路径
    if s == (0, 0, 3, 3, -1):
        route.append(s)
        way.append(route[:])
        return

    route.append(s)
    for i in range(len(g[s])):
        dfs(g[s][i])   #递归搜索直到到达终点或者重复
        route.pop()

def main():
    start = [3, 3, 0, 0, 1]
    statusl.append(start)
    result(start)
    dfs(start)
    num = 0   # 统计次数
    # 输出路径
    for k in way:
        num += 1
        print("第%d条路径:" % num)
        print("左传教士,左食人者,右传教士,右食人者,  船 ")
        for i in k:
            print("{}       {}       {}       {}       {}   ".format(i[0], i[1], i[2], i[3], i[4]))
    print("总共有%d条路径" % num)

if __name__ == '__main__':
    main()

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值