深度優先搜索算法(DFS)詳解

DFS即Depth First Search,是一種用於遍歷或搜索樹或圖的算法。 沿着樹的深度遍歷樹的節點,儘可能深的搜索樹的分支。其過程簡要來說是對每一個可能的分支路徑深入到不能再深入爲止,而且每個節點只能訪問一次。

##DFS模塊基本步驟
DFS(dep,...)
{
	if (找到解 or 走不下去了)
	{
		...
		return
	}
	枚舉下一種可能出現的情況,DFS(dep+1,...)
}

例題

地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?

思路:利用回溯法遍歷所有元素,記錄滿足條件的路徑,爲了簡單起見,我們可以只從兩個方向尋找,向右與向下。需要注意的是邊界條件。

class Solution3:
    def movingCount(self, threshold, rows, cols):
        # 計算每一位之和
        def getsum(num):
            sum = 0
            while num>0:
                sum += num%10
                num = num//10
            return sum
        path = []
        def back(start):
            if start in path or getsum(start[0]) + getsum(start[1])> threshold:
                return None
            if start[0]>=rows or start[1]>=cols:
                return None
            path.append(start)       # 從0,0開始向右向下遍歷,減少走回頭路的次數
            print(path)
            back([start[0]+1,start[1]])
            back([start[0],start[1]+1])

            """
            if start[0]>=rows or start[1]>=cols or start[0]<0 or start[1]<0:
                return None
            path.append(start)       # 從0,0開始向右向下遍歷,減少走回頭路的次數            
            back([start[0]+1,start[1]])
            back([start[0]-1,start[1]])
            back([start[0],start[1]-1])
            back([start[0],start[1]+1])
            """

        back([0,0])
        return len(path)

print(Solution3().movingCount(4,3,5))

方法二

與方法一種保存每一條符合條件的路徑不同,該方法是通過構建一個同等大小的矩陣,記錄走過的路徑,然後在四個方向深度搜索。

class Solution2:
    def __init__(self):
        self.count = 0

    def movingCount(self, threshold, rows, cols):
        # write code here
        arr = [[1 for i in range(cols)] for j in range(rows)]
        self.findway(arr, 0, 0, threshold)
        return self.count

    def findway(self, arr, i, j, k):
        if i < 0 or j < 0 or i >= len(arr) or j >= len(arr[0]):
            return
        tmpi = list(map(int, list(str(i))))  # 將一個整型數字轉化字符串類型,然後在列表化,最後在轉化爲整型。 12——[1,2]
        tmpj = list(map(int, list(str(j))))
        if sum(tmpi) + sum(tmpj) > k or arr[i][j] != 1:
            return
        arr[i][j] = 0  #記錄走過的路徑
        self.count += 1
        self.findway(arr, i + 1, j, k)
        self.findway(arr, i - 1, j, k)
        self.findway(arr, i, j + 1, k)
        self.findway(arr, i, j - 1, k)

方法三

1、從(0,0)開始走,每成功走一步標記當前位置爲true,然後從當前位置往四個方向探索,
返回1 + 4 個方向的探索值之和。

2、探索時,判斷當前節點是否可達的標準爲:
1)當前節點在矩陣內;
2)當前節點未被訪問過;
3)當前節點滿足limit限制。

class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        if not threshold or not rows or not cols:
            return 0
        # 定義每格標誌位:  0代表沒走過;  1代表走過
        visited = [0]*(rows * cols)
        for row in range(rows):
            for col in range(cols):
                
                return self.movingCountCore(threshold, rows, cols, row, col, visited)

    # 數字數位求和函數
    def digitSum(self, dig):
        re = 0
        while dig:
            re = re + dig % 10
            dig = dig // 10
        return re

    # 遞歸回溯判斷每步是否可行,並返回計數和累加
    def movingCountCore(self, threshold, rows, cols, row, col, visited):
        count = 0
        if 0 <= row < rows and 0 <= col < cols\
                and self.digitSum(row) + self.digitSum(col) <= threshold and visited[row * cols + col] == 0:
            visited[row * cols + col] = 1
            print("visited:",visited)

            # 在遞歸中,依次遍歷每個元素的上下左右四個元素,如果滿足條件,則繼續遞歸,遞歸過的每一個元素都進行標記
            count = 1 + self.movingCountCore(threshold, rows, cols, row - 1, col, visited) \
                      + self.movingCountCore(threshold, rows, cols, row + 1, col, visited) \
                      + self.movingCountCore(threshold, rows, cols, row, col - 1, visited) \
                      + self.movingCountCore(threshold, rows, cols, row, col + 1, visited)
            print("count:",count)
        return count

# print(Solution().movingCount(10,7,7))

總結

類似的求路徑都可以用這種無腦深度優先搜索法去解決,即回溯的思想,需要注意的是遞歸的終止條件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章