国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS),用代碼講原理

這篇具有很好參考價(jià)值的文章主要介紹了深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS),用代碼講原理。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

以圖文的形式對(duì)深度搜索和廣度搜索的理論進(jìn)行講解時(shí),可能會(huì)對(duì)一些概念有些模糊,且不太清楚怎么把該理論用程序的方式進(jìn)行復(fù)現(xiàn)并解決這一搜索問題(這說的就是本人)。所以后面我看完了一份實(shí)現(xiàn)這兩種搜索方法的代碼,在這做一個(gè)筆記,希望對(duì)大家有所幫助。


深度搜索和廣度搜索的區(qū)別

兩者本質(zhì)的區(qū)別就是一個(gè)找下一個(gè)節(jié)點(diǎn)時(shí)是做的堆棧(先進(jìn)后出),一個(gè)是做隊(duì)列(先進(jìn)先出)。我們用for循環(huán)和一個(gè)列表來簡(jiǎn)單說明理解一下。這里可能說的不好,如果給大家說模糊了可以不用看

li = []
for i in range(5):
    li.append(i)
print(li) # ==>結(jié)果[0,1,2,3,4]

?1.1 深度優(yōu)先搜索的堆棧

上面的for循環(huán)程序中,列表里面的0是第一個(gè)進(jìn)去的,4是最后一個(gè)進(jìn)去的,所以我們?cè)谶x擇下一個(gè)點(diǎn)時(shí)就會(huì)選擇4。選擇過程也是取列表的最后一位,并將其從列表中刪除

state = li[-1] # 選擇下一步的位置狀態(tài)(當(dāng)作是坐標(biāo)和行動(dòng)方向)
li = li[:-1] # 選中后的狀態(tài)會(huì)進(jìn)入程序運(yùn)算,所以這從列表中刪除選擇后的點(diǎn)
print(li) # ==> [0,1,2,3]

?1.2 廣度優(yōu)先搜索的隊(duì)列

我們的隊(duì)列,簡(jiǎn)單的說就是排隊(duì),誰先進(jìn)入列表,那么在下一次選擇動(dòng)作節(jié)點(diǎn)時(shí)就優(yōu)先被選中。

state = li[0] # 取列表的第一個(gè)節(jié)點(diǎn)狀態(tài)(同坐標(biāo)和行動(dòng)方向)
li = li[-1] # 選取后進(jìn)入程序運(yùn)算,并從列表中刪除該狀態(tài)點(diǎn)
print(li) # ==> [1,2,3,4]

探索集?

在程序搜索過程中保存我們已經(jīng)探索過的所有節(jié)點(diǎn)坐標(biāo),在程序中會(huì)一直對(duì)這個(gè)集合進(jìn)行判斷,保證不會(huì)在子節(jié)點(diǎn)和父節(jié)點(diǎn)之間來回探索,創(chuàng)建形式如下代碼。

explore = set() # 創(chuàng)建探索集合

深度優(yōu)先搜索

2.1? 數(shù)據(jù)形式及處理

本文所采用的數(shù)據(jù)形式為txt文本,文本中內(nèi)容如下:

 *****

 ** **
 **B**
 *  **
 * ***
A  ***

數(shù)據(jù)由A、B、*號(hào)和空格組成,其中*號(hào)表示不可通行的墻,A是我們的起始點(diǎn),B是我們的目標(biāo)點(diǎn),空格表示可通行的點(diǎn)。

用代碼實(shí)現(xiàn)數(shù)據(jù)處理并轉(zhuǎn)換為坐標(biāo)形式,如下所示:

class Maze():

    def __init__(self, filename):

        # Read file and set height and width of maze
        """
        初始化操作,找到文件中的起點(diǎn)a和終點(diǎn)b是否存在
        存在進(jìn)行行列的遍歷,找到A,B在文本中的坐標(biāo)點(diǎn)
        :param filename:我們傳入的txt文本,文本內(nèi)容如上所示 

        """
        with open(filename) as f:
            contents = f.read()

        # Validate start and goal 判斷是否存在起始點(diǎn)和目標(biāo)點(diǎn)位,不存在退出程序
        if contents.count("A") != 1:
            raise Exception("maze must have exactly one start point")
        if contents.count("B") != 1:
            raise Exception("maze must have exactly one goal")

        # Determine height and width of maze 找到文本的長(zhǎng)寬,做循環(huán)起到記錄坐標(biāo)點(diǎn)的作用
        contents = contents.splitlines()
        self.height = len(contents)
        self.width = max(len(line) for line in contents)

        # Keep track of walls
        self.walls = []
        # 這里循環(huán)找到所有坐標(biāo),及A、B、*號(hào)和空格所在的坐標(biāo)點(diǎn)并保存
        for i in range(self.height):
            row = []
            for j in range(self.width):
                try:
                    if contents[i][j] == "A":
                        self.start = (i, j)
                        row.append(False)
                    elif contents[i][j] == "B":
                        self.goal = (i, j)
                        row.append(False)
                    elif contents[i][j] == " ":
                        row.append(False)
                    else:
                        row.append(True)
                except IndexError:
                    row.append(False)
            self.walls.append(row)

        self.solution = None

代碼解釋(有編程經(jīng)驗(yàn)的看上面代碼即可 ):我們向Maze類里面?zhèn)魅胛覀兊膖xt文本,打開并讀取其中的內(nèi)容。對(duì)內(nèi)容進(jìn)行判斷(是否存在起始點(diǎn)和目標(biāo)點(diǎn))。獲取內(nèi)容的高度和寬度,本文所傳入的高寬為 7*5 (最上面那個(gè)很多*號(hào)的就是)。循環(huán)高度和寬度,找到A點(diǎn)和B點(diǎn)的坐標(biāo),將空格和A、B點(diǎn)在row列表中保存為False,*號(hào)保存為True,最后將每一行的row列表保存到self.wall的列表當(dāng)中。在后續(xù)找點(diǎn)時(shí)判斷self.wall[i][j]及第 i 行第 j 列的布爾值是否為True,是則代表無法通行。

2.2節(jié)點(diǎn)保存、路徑搜索及路徑回溯

我們可以通過PIL庫(kù)中的Image, ImageDraw,將以上處理結(jié)果轉(zhuǎn)換為圖片的形式,紅色代表起始點(diǎn),綠色代表目標(biāo)點(diǎn),白色為可以通過的節(jié)點(diǎn)。我們?cè)诤罄m(xù)過程都以下圖為例。

深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS),用代碼講原理,深度優(yōu)先,算法,廣度優(yōu)先,python

2.2.1 節(jié)點(diǎn)保存

我們使用class類的方式保存當(dāng)前狀態(tài)坐標(biāo)、行動(dòng)的方向和父節(jié)點(diǎn)(父節(jié)點(diǎn)也是這個(gè)類,也存著坐標(biāo)、行動(dòng)和父節(jié)點(diǎn)),代碼如下:

class Node():
    def __init__(self, state, parent, action):
        self.state = state
        self.parent = parent
        self.action = action

?我們每在后面while循環(huán)實(shí)例化該類時(shí),都會(huì)在內(nèi)存中有記錄。可以看python類的基礎(chǔ)知識(shí)

2.2.2 路徑搜索

    def neighbors(self, state):
        """
        在調(diào)用這個(gè)函數(shù)的時(shí)候會(huì)傳入當(dāng)前狀態(tài)的坐標(biāo)點(diǎn)。也就是我們?cè)诔绦蛑?        自己定義下一步優(yōu)先走的方向,在candidates列表里面就是上下左右的
        順序進(jìn)行移動(dòng) 以點(diǎn)(0,0)為例,得到的candidates列表就是
        [
        "up",(-1,0),
        "down",(1,0),
        "left",(0,-1),
        "right",(0,1)    
        ]
        得到行動(dòng)列表后開始進(jìn)行循環(huán)判斷,判斷是否超出長(zhǎng)和寬,以及self.wall[r][c]是否為True,
        如果都不滿足就代表可以行動(dòng),添加到result列表
        """
        row, col = state
        candidates = [
            ("up", (row - 1, col)),
            ("down", (row + 1, col)),
            ("left", (row, col - 1)),
            ("right", (row, col + 1))
        ]

        result = []
        # 保存可以走的方向, 判斷是否在邊界以及是否有墻 self.wall列表中的是bool
        for action, (r, c) in candidates:
            if 0 <= r < self.height and 0 <= c < self.width and not self.walls[r][c]:
                result.append((action, (r, c)))
        return result


    def solve(self):
        """Finds a solution to maze, if one exists."""

        # Keep track of number of states explored
        self.num_explored = 0

        # Initialize frontier to just the starting position
        # 初始化起始點(diǎn)的節(jié)點(diǎn),并將其保存到StackFrontier()類里面的frontier列表當(dāng)中(保存的是一個(gè)對(duì)象)
        
        start = Node(state=self.start, parent=None, action=None)
        frontier = StackFrontier()
        frontier.add(start)

        # Initialize an empty explored set 初始化探索集
        self.explored = set()

        # Keep looping until solution found 循環(huán)查找路徑
        while True:
            # If nothing left in frontier, then no path
            if frontier.empty():
                raise Exception("no solution")

            # Choose a node from the frontier
  
            # 獲取并子節(jié)點(diǎn)(坐標(biāo)和行動(dòng)方向,以及父節(jié)點(diǎn))并從邊界列表中刪除該節(jié)點(diǎn)(具體看StackFrontier類的remove函數(shù)),其過程與最開始的堆棧列表過程相同
            node = frontier.remove()
            self.num_explored += 1

            # If node is the goal, then we have a solution
            if node.state == self.goal:
                actions = []
                cells = []
                # while循環(huán)對(duì)路徑進(jìn)行回溯(過程在文中進(jìn)行簡(jiǎn)紹)
                while node.parent is not None:
                    actions.append(node.action)
                    cells.append(node.state)
                    node = node.parent
                print(cells)
                actions.reverse()
                cells.reverse()
                self.solution = (actions, cells)
                return

            # Mark node as explored
            self.explored.add(node.state)

            # Add neighbors to frontier 返回的執(zhí)行列表是 先上 后下
            for action, state in self.neighbors(node.state):
                if not frontier.contains_state(state) and state not in self.explored:
                    # state 和 action保存的是子節(jié)點(diǎn)的行動(dòng)和狀態(tài),而parent保存了父節(jié)點(diǎn)的所有狀態(tài),比如從起始點(diǎn)到第二個(gè)點(diǎn),parent保存的就是起始狀態(tài)的所有狀態(tài)
                    child = Node(state=state, parent=node, action=action)

                    frontier.add(child)
class StackFrontier():
    def  __init__(self):
        self.frontier = []
    def add(self, node):
        self.frontier.append(node)

    def contains_state(self, state):
        return any(node.state == state for node in self.frontier)

    def empty(self):
        return len(self.frontier) == 0

    def  remove(self):
        # 堆棧,先進(jìn)后出 深度搜索
        if self.empty():
            raise Exception("empty frontier")
        else:
            # 取列表中最后一個(gè)對(duì)象,并將邊界列表的最后一個(gè)刪除,返回結(jié)果為對(duì)象(對(duì)象中有當(dāng)前節(jié)點(diǎn)、運(yùn)動(dòng)方向和他的父節(jié)點(diǎn))
            node = self.frontier[-1]
            self.frontier = self.frontier[:-1]
            return node

上述代碼是存在于Maze類當(dāng)中,函數(shù)neighbors是查找當(dāng)前坐標(biāo)點(diǎn)上下左右4個(gè)方向的坐標(biāo),并判斷是否可以通過,如果可以就保存到result列表當(dāng)中,并返回result列表。

?solve函數(shù)是判斷是否到達(dá)目標(biāo)點(diǎn)的函數(shù), 可以看程序中的注釋進(jìn)行了解。我們運(yùn)行整體程序后得到一下結(jié)果的路徑圖,我們看圖講解一下過程。

深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS),用代碼講原理,深度優(yōu)先,算法,廣度優(yōu)先,python

本圖為深度優(yōu)化搜索得到的結(jié)果,如果了解了上面對(duì)程序的解釋,那么我們看后面的內(nèi)容應(yīng)該會(huì)比較容易。

同理紅色代表我們的起始點(diǎn)A,綠色代表我們的目標(biāo)點(diǎn)B,藍(lán)色是我們深度優(yōu)化搜索算法得到的路徑,白色為為探索的路徑。? 我們來講一下程序在這圖片中的路徑搜索過程。

以起始點(diǎn)為例A(6,0),經(jīng)過初始化節(jié)點(diǎn)的Node類保存起始點(diǎn)的坐標(biāo)(起始點(diǎn)無父節(jié)點(diǎn)和行動(dòng)方向),將A點(diǎn)傳入以下程序中尋找可移動(dòng)的方向和節(jié)點(diǎn)

    def neighbors(self, state):
        """
        在調(diào)用這個(gè)函數(shù)的時(shí)候會(huì)傳入當(dāng)前狀態(tài)的坐標(biāo)點(diǎn)。也就是我們?cè)诔绦蛑?        自己定義下一步優(yōu)先走的方向,在candidates列表里面就是上下左右的
        順序進(jìn)行移動(dòng) 以點(diǎn)(0,0)為例,得到的candidates列表就是
        [
        "up",(-1,0),
        "down",(1,0),
        "left",(0,-1),
        "right",(0,1)    
        ]
        得到行動(dòng)列表后開始進(jìn)行循環(huán)判斷,判斷是否超出長(zhǎng)和寬,以及self.wall[r][c]是否為True,
        如果都不滿足就代表可以行動(dòng),添加到result列表
        """
        row, col = state
        candidates = [
            ("up", (row - 1, col)),
            ("down", (row + 1, col)),
            ("left", (row, col - 1)),
            ("right", (row, col + 1))
        ]

        result = []
        # 保存可以走的方向, 判斷是否在邊界以及是否有墻 self.wall列表中的是bool
        for action, (r, c) in candidates:
            if 0 <= r < self.height and 0 <= c < self.width and not self.walls[r][c]:
                result.append((action, (r, c)))
        return result

? ? ? ?得到列表結(jié)果為:? [ ("up",(5,0)),( "down",(7,0)),("left",(6,-1)), ("right",(6,1)) ],

將得到的列表再經(jīng)過for循環(huán)判斷是否超出原文本的長(zhǎng)寬,以及是否為墻,如果滿足其中一項(xiàng)就表示該節(jié)點(diǎn)無法通過,比如節(jié)點(diǎn) (“down”,(7,0))超出了我們整體的高度及超出了二維矩陣的索引(高度是從0開始到6結(jié)尾,整體高為7)這個(gè)節(jié)點(diǎn)就不會(huì)被保存進(jìn)result列表

因此從A點(diǎn)開始可以通過的節(jié)點(diǎn)為 result = [("up",(5,0)),("right",(6,1))]。得到的結(jié)果返回到for循環(huán)中,如下程序:

             for action, state in self.neighbors(node.state):
                if not frontier.contains_state(state) and state not in self.explored:
                    # state 和 action保存的是子節(jié)點(diǎn)的行動(dòng)和狀態(tài),而parent保存了父節(jié)點(diǎn)的所有狀態(tài),比如從起始點(diǎn)到第二個(gè)點(diǎn),parent保存的就是起始狀態(tài)的所有狀態(tài)
                    child = Node(state=state, parent=node, action=action)

                    frontier.add(child)

在本段程序中會(huì)將兩個(gè)子節(jié)點(diǎn)保存到Node類中,并將child這個(gè)對(duì)象保存到邊界列表中(邊界列表在StackFrontier類中)。深度優(yōu)先搜索會(huì)在下一次的while循環(huán)中去找StackFrontier類中邊界列表中最后一個(gè)對(duì)象,并賦予變量node,然后重置邊界列表(就是刪除取出來的最后一位對(duì)象)。然后開始重復(fù)上方可行動(dòng)節(jié)點(diǎn)的搜索,找到便保存到邊界列表,沒有就會(huì)在邊界列表中已有的對(duì)象去查找可移動(dòng)節(jié)點(diǎn)。

?2.2.3 回溯

?我們已經(jīng)知道每找到一個(gè)節(jié)點(diǎn)在重新中都會(huì)對(duì)其做一次對(duì)象保存(保存在Node類里),其中保存的內(nèi)容為該節(jié)點(diǎn)的坐標(biāo)和父節(jié)點(diǎn)運(yùn)動(dòng)的該節(jié)點(diǎn)的方向,以及父節(jié)點(diǎn)的對(duì)象。我們看下方程序,就是在while循環(huán)判斷是否存在父節(jié)點(diǎn),存在的情況下找到當(dāng)前節(jié)點(diǎn)的坐標(biāo),并將該節(jié)點(diǎn)的父節(jié)點(diǎn)重新賦值給到node變量,直到回溯到我們的起始點(diǎn)節(jié)點(diǎn)。

回溯程序

       # 判罰是否到達(dá)我們的目標(biāo)點(diǎn)  
       if node.state == self.goal:
                actions = []
                cells = []
                # 開是while循環(huán)判斷回溯,判斷我們類里面是否有父節(jié)點(diǎn)(在起始點(diǎn)的時(shí)候我們沒有父節(jié)點(diǎn)的)
                while node.parent is not None:
                    # 將回溯節(jié)點(diǎn)進(jìn)行保存
                    actions.append(node.action)
                    cells.append(node.state)
                    # 重新對(duì)變量node進(jìn)行賦值,得到當(dāng)前節(jié)點(diǎn)父節(jié)點(diǎn)
                    node = node.parent

起始點(diǎn)的節(jié)點(diǎn)

# 在循環(huán)查找路徑前我們就已經(jīng)將我們的起始點(diǎn)進(jìn)行保存(parent代表我們的父節(jié)點(diǎn),在這里是None,代表沒有,起到while回溯退出的作用)
start = Node(state=self.start, parent=None, action=None)

?看一看回溯過程

"""
    以起始點(diǎn)和他的一個(gè)子節(jié)點(diǎn)為例
"""

start = Node(state=(6,0),parent=None,action=None)

# parent保存的是節(jié)點(diǎn)對(duì)象
child = Node(state=(6,1),parent=start,action='right')

node = child 

action = []
cells = []

while node.parent is not None:
    action.append(node.action)
    cells.append(node.state)
    node = node.parent  # node.parent = Node(state=(6,0),parent=None,action=None)

?廣度優(yōu)先搜索

我們的廣度優(yōu)先搜索的處理過程和深度優(yōu)先搜索相同,唯一不同的地方是在下方StackFrontier類的remove函數(shù)當(dāng)中,需要更改為取列表的第一位,及索引0

class StackFrontier():
    def  __init__(self):
        self.frontier = []
    def add(self, node):
        self.frontier.append(node)

    def contains_state(self, state):
        return any(node.state == state for node in self.frontier)

    def empty(self):
        return len(self.frontier) == 0

    def  remove(self):
        # 堆棧,先進(jìn)后出 深度搜索
        if self.empty():
            raise Exception("empty frontier")
        else:
            # 取列表中最后一個(gè)對(duì)象,并將邊界列表的最后一個(gè)刪除,返回結(jié)果為對(duì)象(對(duì)象中有當(dāng)前節(jié)點(diǎn)、運(yùn)動(dòng)方向和他的父節(jié)點(diǎn))
            node = self.frontier[-1]
            self.frontier = self.frontier[:-1]
            return node

函數(shù)更改,將上方remove函數(shù)改為以下代碼:

    def remove(self):
        if self.empty():
            raise Exception("empty frontier")
        else:
            # 這里取了邊界列表的第一位
            node = self.frontier[0]
            print(node)
            # 這里刪除了邊界列表的第一位
            self.frontier = self.frontier[1:]
            return node

?在尋找節(jié)點(diǎn)的時(shí)候和深度搜索相同,只是按照所有節(jié)點(diǎn)進(jìn)入邊界列表的順序來進(jìn)行下一步的行動(dòng)。

下圖是廣度優(yōu)先搜索得出的結(jié)果圖:

深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS),用代碼講原理,深度優(yōu)先,算法,廣度優(yōu)先,python

?粉紅色為探索過的路徑

?總結(jié)

寫完感覺整篇文章的邏輯和內(nèi)容有點(diǎn)混亂,本人對(duì)兩者算法的理解也有限,可能存在理解錯(cuò)誤的地方,如果導(dǎo)致您感到困惑地方還望理解。

完整代碼如下

##############################
#Maze.py
#Introdution:
#IDE:
#From
#By:qin,2023....
##############################

import sys
import matplotlib.pyplot as plt


#類:
class Node():
    def __init__(self, state, parent, action):
        self.state = state
        self.parent = parent
        self.action = action


class StackFrontier():
    def  __init__(self):
        self.frontier = []
    def add(self, node):
        self.frontier.append(node)

    def contains_state(self, state):
        return any(node.state == state for node in self.frontier)

    def empty(self):
        return len(self.frontier) == 0

    # def  remove(self):
    #     # 堆棧,先進(jìn)后出 深度搜索
    #     if self.empty():
    #         raise Exception("empty frontier")
    #     else:
    #         node = self.frontier[-1]
    #         self.frontier = self.frontier[:-1]
    #         return node
    def remove(self):
        if self.empty():
            raise Exception("empty frontier")
        else:
            node = self.frontier[0]
            print(node)
            self.frontier = self.frontier[1:]
            return node


class QueueFrontier(StackFrontier):
    # 隊(duì)列 先進(jìn)先出,進(jìn)行廣度搜索
    def remove(self):
        if self.empty():
            raise Exception("empty frontier")
        else:
            node = self.frontier[0]
            print(node)
            self.frontier = self.frontier[1:]
            return node

class Maze():

    def __init__(self, filename):

        # Read file and set height and width of maze
        """
        初始化操作,找到文件中的起點(diǎn)a和終點(diǎn)b是否存在
        存在進(jìn)行行列的遍歷,找到A,B在文本中的坐標(biāo)點(diǎn)
        :param filename:

        """
        with open(filename) as f:
            contents = f.read()

        # Validate start and goal
        if contents.count("A") != 1:
            raise Exception("maze must have exactly one start point")
        if contents.count("B") != 1:
            raise Exception("maze must have exactly one goal")

        # Determine height and width of maze
        contents = contents.splitlines()
        self.height = len(contents)
        self.width = max(len(line) for line in contents)

        # Keep track of walls
        self.walls = []
        for i in range(self.height):
            row = []
            for j in range(self.width):
                try:
                    if contents[i][j] == "A":
                        self.start = (i, j)
                        row.append(False)
                    elif contents[i][j] == "B":
                        self.goal = (i, j)
                        row.append(False)
                    elif contents[i][j] == " ":
                        row.append(False)
                    else:
                        row.append(True)
                except IndexError:
                    row.append(False)
            self.walls.append(row)

        self.solution = None


    def print(self):
        solution = self.solution[1] if self.solution is not None else None
        print()
        for i, row in enumerate(self.walls):
            for j, col in enumerate(row):
                if col:
                    print("█", end="")
                elif (i, j) == self.start:
                    print("A", end="")
                elif (i, j) == self.goal:
                    print("B", end="")
                elif solution is not None and (i, j) in solution:
                    print("*", end="")
                else:
                    print(" ", end="")
            print()
        print()


    def neighbors(self, state):
        row, col = state
        candidates = [
            ("up", (row - 1, col)),
            ("down", (row + 1, col)),
            ("left", (row, col - 1)),
            ("right", (row, col + 1))
        ]

        result = []
        # 保存可以走的方向, 判斷是否在邊界以及是否有墻 self.wall列表中的是bool
        for action, (r, c) in candidates:
            if 0 <= r < self.height and 0 <= c < self.width and not self.walls[r][c]:
                result.append((action, (r, c)))
        return result


    def solve(self):
        """Finds a solution to maze, if one exists."""

        # Keep track of number of states explored
        self.num_explored = 0

        # Initialize frontier to just the starting position
        start = Node(state=self.start, parent=None, action=None)
        print("起始點(diǎn)的坐標(biāo)",start.state)
        frontier = StackFrontier()
        frontier.add(start)

        # Initialize an empty explored set
        self.explored = set()

        # Keep looping until solution found
        while True:
            # If nothing left in frontier, then no path
            if frontier.empty():
                raise Exception("no solution")

            # Choose a node from the frontier
            r = QueueFrontier()
            node = frontier.remove()
            self.num_explored += 1

            # If node is the goal, then we have a solution
            if node.state == self.goal:
                actions = []
                cells = []
                while node.parent is not None:
                    actions.append(node.action)
                    cells.append(node.state)
                    node = node.parent
                print(cells)
                actions.reverse()
                cells.reverse()
                self.solution = (actions, cells)
                return

            # Mark node as explored
            self.explored.add(node.state)

            # Add neighbors to frontier 返回的執(zhí)行列表是 先上 后下
            for action, state in self.neighbors(node.state):
                if not frontier.contains_state(state) and state not in self.explored:
                    # state 和 action保存的是子節(jié)點(diǎn)的行動(dòng)和狀態(tài),而parent保存了父節(jié)點(diǎn)的所有狀態(tài),比如從起始點(diǎn)到第二個(gè)點(diǎn),parent保存的就是起始狀態(tài)的所有狀態(tài)
                    child = Node(state=state, parent=node, action=action)

                    frontier.add(child)


    def output_image(self, filename, show_solution=True, show_explored=False):
        from PIL import Image, ImageDraw
        cell_size = 50
        cell_border = 2
        # 創(chuàng)建圖像畫布,將start 、goal、wall和路徑用不同的像素表示
        # Create a blank canvas
        img = Image.new(
            "RGBA",
            (self.width * cell_size, self.height * cell_size),
            "black"
        )
        draw = ImageDraw.Draw(img)

        solution = self.solution[1] if self.solution is not None else None
        for i, row in enumerate(self.walls):
            for j, col in enumerate(row):
                # plt.clf()

                # Walls
                if col:
                    fill = (40, 40, 40)

                # Start
                elif (i, j) == self.start:
                    fill = (255, 0, 0)
                    # plt.imshow(img)
                    # plt.pause(0.4)

                # Goal
                elif (i, j) == self.goal:
                    fill = (0, 171, 28)

                # Solution
                elif solution is not None and show_solution and (i, j) in solution:
                    fill = (120, 200, 252)
                    # plt.imshow(img)
                    # plt.pause(0.4)

                # Explored
                elif solution is not None and show_explored and (i, j) in self.explored:
                    fill = (255, 100, 120)

                # Empty cell
                else:
                    fill = (237, 255, 252)

                # Draw cell
                draw.rectangle(
                    ([(j * cell_size + cell_border, i * cell_size + cell_border),
                      ((j + 1) * cell_size - cell_border, (i + 1) * cell_size - cell_border)]),
                    fill=fill
                )
                # plt.imshow(img)
                # plt.pause(0.4)
        # plt.ioff()
        # plt.show()
        img.save(filename)

# for i in range(4):
#     sys.argv.append(f"./maze{i+1}.txt")
# 
# 
# if len(sys.argv) < 2:
#     sys.exit("Usage: python maze.py maze.txt1")
# 
# 
# print((sys.argv))


# path = sys.argv[j+1]
m = Maze('./maze1.txt')
print("Maze:")
m.print()
print("Solving...")
m.solve()
print("States Explored:", m.num_explored)
print("Solution:")
m.print()
m.output_image(f"maze.png", show_explored=True)

上述代碼非本人編寫,僅用于講述與教學(xué)文章來源地址http://www.zghlxwxcb.cn/news/detail-848881.html

到了這里,關(guān)于深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS),用代碼講原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包