🧡🧡实验内容🧡🧡
有n个牧师和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯牧师,要求无论在何处,牧师的人数不得少于野人的人数(除非牧师人数为0),且假定野人与牧师都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出小船来回次数最少的最佳方案。
输入:牧师人数(即野人人数):n;小船一次最多载人量:c。
输出:若问题无解,则显示Failed,否则,显示Successed输出所有可行方案,并标注哪一组是最佳方案。用三元组(X1, X2, X3)表示渡河过程中的状态。并用箭头连接相邻状态以表示迁移过程:初始状态->中间状态->目标状态。
例:当输入n=2,c=2时,输出:221->200->211->010->021->000;
其中:X1表示起始岸上的牧师人数;X2表示起始岸上的野人人数;X3表示小船现在位置(1表示起始岸,0表示目的岸)。
Please input n: 2 Please input c: 2
Optimal Procedure: 221->200->211->010->021->000
Successed or Failed?: Successed
🧡🧡实现🧡🧡
状态的数据结构:
class State:
    def __init__(self, Lsavage, Lmissionary, Rsavage, Rmissionary, boat):
        self.Lsavage = Lsavage # 左边野人数目
        self.Lmissionary = Lmissionary # 左边野人数目
        self.Rsavage = Rsavage
        self.Rmissionary = Rmissionary
        self.boat = boat  # 0: 左边   1:右边
结果解释
👇初始状态为(2,2,1)👇
👇初始状态为(3,3,1)👇
完整程序
class State:
    def __init__(self, Lsavage, Lmissionary, Rsavage, Rmissionary, boat):
        self.Lsavage = Lsavage # 左边野人数目
        self.Lmissionary = Lmissionary # 左边野人数目
        self.Rsavage = Rsavage
        self.Rmissionary = Rmissionary
        self.boat = boat  # 0: 左边   1:右边
def boating(i,s,m): # s个野人 和 m个传教士
    if States[i].boat==1:  # 船在右边,准备往左边送
        States[i+1].Rsavage=States[i].Rsavage-s
        States[i+1].Rmissionary=States[i].Rmissionary-m
        States[i+1].Lsavage=States[i].Lsavage+s
        States[i+1].Lmissionary=States[i].Lmissionary+m
        States[i+1].boat=0
    else:                 # 船在左边,准备往右边送
        States[i+1].Lsavage=States[i].Lsavage-s
        States[i+1].Lmissionary=States[i].Lmissionary-m
        States[i+1].Rsavage=States[i].Rsavage+s
        States[i+1].Rmissionary=States[i].Rmissionary+m
        States[i+1].boat=1
def check(state): # 检查是否是正确的状态
    if state.Rmissionary>0 and state.Rmissionary<state.Rsavage:
        return False
    elif state.Lmissionary>0 and state.Lmissionary<state.Lsavage:
        return False
    else:
        return True
def saveSolution(i): # 保存路径
    path=""
    for j in range(0,i+1):
        path+=str(States[j].Rmissionary)+str(States[j].Rsavage)+str(States[j].boat)
        if j!=i:
            path+="->"
        else:
            path+="\n"
    all_path.add(path)
def dfs(i):
    # 终止条件
    if i >= 150:
        return
    for j in range(0, i):  # 保证没有重复状态
        if States[j].Lsavage == States[i].Lsavage and \
                States[j].Lmissionary == States[i].Lmissionary and \
                States[j].Rsavage == States[i].Rsavage and \
                States[j].Rmissionary == States[i].Rmissionary and \
                States[j].boat == States[i].boat:
            return
    if States[i].Rsavage == 0 and States[i].Rmissionary == 0 and States[i].boat == 0:  # 目标状态
        saveSolution(i)
        return
    # 递归  s: 野人个数, m:传教士个数, c:船的最大载量
    if States[i].boat == 1:  # -- 船在右边
        for s in range(1, c + 1 if c < States[i].Rsavage else States[i].Rsavage + 1):  # 先让野人上船
            m = 0
            boating(i, s, m)
            if check(States[i + 1]):
                dfs(i + 1)
        for m in range(1, c + 1 if c < States[i].Rmissionary else States[i].Rmissionary + 1):  # 再让传教士上船
            for s in range(m + 1):
                if s <= c - m and s <= States[i].Rsavage:
                    boating(i, s, m)
                    if check(States[i + 1]):
                        dfs(i + 1)
    else:  # -- 船在左边
        for s in range(1, c + 1 if c < States[i].Lsavage else States[i].Lsavage + 1):
            m = 0
            boating(i, s, m)
            if check(States[i + 1]):
                dfs(i + 1)
        for m in range(1, c + 1 if c < States[i].Lmissionary else States[i].Lmissionary + 1):
            for s in range(m + 1):
                if s <= c - m and s <= States[i].Lsavage:
                    boating(i, s, m)
                    if check(States[i + 1]):
                        dfs(i + 1)
if __name__ == "__main__":
    n = eval(input("请输入野人和传教士的的人数 n="))
    c = eval(input("请输入船的最大载量 c="))
    States = [State(0, 0, 0, 0, 0) for _ in range(150)]  # 初始化状态
    States[0].Rsavage = States[0].Rmissionary = n
    States[0].Lsavage = States[0].Lmissionary = 0
    States[0].boat = 1  # 船一开始在右边
    all_path = set()  # 初始化路径
    dfs(0)  # 递归
    # 打印结果
    if not all_path:
        print("无解")
    else:
        print(f"\n{len(all_path)}条可行路径:")
        for p in all_path:
            print(p, end="")
        print("\n最佳路径(次数最少):")
        print(min(all_path, key=len))
🧡🧡总结🧡🧡
1.当船载量设置为2时:
野人和传教士人数为2时,程序输出结果如下👇
野人和传教士人数为3时,程序输出结果如下👇
野人和传教士人数为4时,程序输出结果如下👇
野人和传教士人数>=4时,均是无解
2.当船载量设置为3时:
野人和传教士人数为2时,程序输出结果如下👇
野人和传教士人数为3时,程序输出结果如下👇
野人和传教士人数为4时,程序输出结果如下👇
野人和传教士人数为5时,程序输出结果如下👇
野人和传教士人数为>=6 时,程序输出结果如下👇


































