传教士过河算法(Python)


记录一下几个月前写的传教士过河问题,网上称为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')

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM