傳教士過河算法(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