🧡🧡实验内容🧡🧡
有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 时,程序输出结果如下👇