记录一下几个月前写的传教士过河问题,网上称为mc问题。
在河的左岸有N个传教士、N个野人和一条船,传教士们想用这条船把所有人都运过河去,但有以下条件限制:
(1)传教士和野人都会划船,但船每次最多只能运K个人;
(2)在任何岸边野人数目都不能超过传教士,否则传教士会被野人吃掉。假定野人会服从任何一种过河安排,请规划出一个确保传教士安全过河的计划。
那么首先定义状态节点,这个节点里包含了包含了左岸传教士、野人、船的状态。如下:
class NODE: def __init__(self,lm,lc,flag): self.lm=lm#左岸传教士 self.lc=lc#左岸野人 self.flag=flag#flag==1,船在左岸 self.father=None self.prop=[lm,lc,flag]
接下来就是主体算法:
def DFS(s): global OPEN,CLOSED OPEN.append(s) while OPEN:#open表非空 op_fst=OPEN[0]#取出第一个元素 if op_fst.prop==end.prop:#判断是否是目标节点 return op_fst OPEN.remove(op_fst) CLOSED.append(op_fst)#open表移除,closed表加入 for i in range(M): for j in range(C): if i+j<=0 or i+j>2 or (i!=0 and i<j):#船上的非法情况 continue if op_fst.flag==1:#船在左岸 cur=NODE(op_fst.lm-i,op_fst.lc-j,0) else:#船在右岸,也是统计左岸mc cur=NODE(op_fst.lm+i,op_fst.lc+j,1) if not chk(cur) or backtrace(cur,op_fst):#状态非法,或者状态循环 pass else:#拓展节点 cur.father=op_fst if inlist(cur,OPEN) or inlist(cur,CLOSED): pass else: OPEN.insert(0,cur) print('open表\n') for item in OPEN: print(item.prop)
DFS函数的输入s就是初始状态,如(3,3,1)表示左岸3个传教士、3个野人和船在左岸。然后就是遍历各种情况,排除非法情况,完善状态节点和OPEN、CLOSED两个表,不断进行迭代,直到满足结束状态即(0,0,0)。然后就是把父节点一路打印出来就是解。
完整代码如下:
OPEN=[] CLOSED=[] M=3 C=3 #一个状态由左岸mc和船上的mc决定 class NODE: def __init__(self,lm,lc,flag): self.lm=lm#左岸传教士 self.lc=lc#左岸野人 self.flag=flag#flag==1,船在左岸 self.father=None self.prop=[lm,lc,flag] def chk(node):#判断正常否 global M,C if node.lm<0 or node.lc<0 or node.lm>M or node.lc>C or (node.lm!=0 and node.lm<node.lc) or (node.lm!=M and M-node.lm<C-node.lc): return False else: return True def backtrace(cur,hypo): if hypo.father is None: return False elif cur.prop==hypo.father.prop: return True else: return False def inlist(a,b): for i in b: if a.prop==i.prop: return True return False def DFS(s): global OPEN,CLOSED OPEN.append(s) while OPEN:#open表非空 op_fst=OPEN[0]#取出第一个元素 if op_fst.prop==end.prop:#判断是否是目标节点 return op_fst OPEN.remove(op_fst) CLOSED.append(op_fst)#open表移除,closed表加入 for i in range(M): for j in range(C): if i+j<=0 or i+j>2 or (i!=0 and i<j):#船上的非法情况 continue if op_fst.flag==1:#船在左岸 cur=NODE(op_fst.lm-i,op_fst.lc-j,0) else:#船在右岸,也是统计左岸mc cur=NODE(op_fst.lm+i,op_fst.lc+j,1) if not chk(cur) or backtrace(cur,op_fst):#状态非法,或者状态循环 pass else:#拓展节点 cur.father=op_fst if inlist(cur,OPEN) or inlist(cur,CLOSED): pass else: OPEN.insert(0,cur) print('open表\n') for item in OPEN: print(item.prop) def printpath(f): if f is None: return print(f.prop) printpath(f.father) start=NODE(M,C,1) end=NODE(0,0,0) p=DFS(start) if p: printpath(p) else: print('no solution')