여름의 서재

[알고리즘 종류] DFS(깊이우선탐색) & BFS(너비우선탐색) 본문

알고리즘/알고리즘 종류

[알고리즘 종류] DFS(깊이우선탐색) & BFS(너비우선탐색)

엉아_ 2021. 8. 13. 23:57
728x90

출처 : https://mygumi.tistory.com/102

- DFS (Depth-first Search)

: 루트 노드에서 시작해서 다음 분기(branch)로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방식

 

ex) 미로찾기를 할 때 최대한 한 방향으로 갈 수 있을 때까지 쭉 가다가 더 이상 갈 수 없게 되면 다시 가장 가까운 갈림길로 돌아와서 그 갈림길부터 다시 다른 방향으로 탐색을 진행하는 것이 깊이 우선 탐색 방식.

 

1. 모든 노드를 방문하고자 하는 경우에 이 방법을 선택함

2. 깊이 우선 탐색(DFS)이 너비 우선 탐색(BFS)보다 좀 더 간단함

3. 검색 속도 자체는 너비 우선 탐색(BFS)에 비해서 느림

 

- stack을 통해서 구현 가능

def DFS(graph, root):
    visited = []
    stack = [root]

    while stack:
        n = stack.pop()
        if n not in visited:
            visited.append(n)
            stack += graph[n] - set(visited)  # 연결된 노드 중 방문한 노드를 빼고 stack에 추가
    return visited
    
 # 애초에 그래프 또한 graph = {1:set(2,3),2:..} 이런 형태여야 함

 

- BFS (Breadth-first Search)

: 시작점인 루트 노드와 같은 거리에 있는 노드를 우선으로 탐색하는 방식

 

주로 두 노드 사이의 최단 경로를 찾고 싶을 때 이 방법을 선택.

ex) 지구 상에 존재하는 모든 친구 관계를 그래프로 표현한 후 Sam과 Eddie사이에 존재하는 경로를 찾는 경우

 

* 깊이 우선 탐색의 경우 - 모든 친구 관계를 다 살펴봐야 할지도 모름

* 너비 우선 탐색의 경우 - Sam과 가까운 관계부터 탐색

 

- deque를 이용해 구현 가능

from collections import deque

def BFS(graph, root):
    visited = []
    queue = deque([root])

    while queue:
        n = queue.popleft()
        if n not in visited:
            visited.append(n)
            queue += graph[n] - set(visited)
    return visited

 

📄 활용 문제

백준 1260_ DFS와 BFS

문제

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 #¹정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

입력

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 #²양방향이다.

출력

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

 

출처 : https://www.acmicpc.net/problem/1260

from collections import deque

def DFS(graph, root):
    visited = []
    stack = [root]

    while stack:
        n = stack.pop()
        if n not in visited:
            visited.append(n)
            if n in graph:
                temp = list(set(graph[n]) - set(visited))
                temp.sort(reverse=True) # 1 작은 것부터 방문하기 위해
                stack += temp
    return visited

def BFS(graph, root):
    visited = []
    queue = deque([root])

    while queue:
        n = queue.popleft()
        if n not in visited:
            visited.append(n)
            if n in graph:
                temp = list(set(graph[n]) - set(visited))
                temp.sort() # 1 작은 것부터 방문하기 위해
                queue += temp
    return visited

graph = {}
node, edge, start = map(int, input().split())

for i in range(edge):
    n1, n2 = map(int, input().split())

    # 2 양방향이기 때문에
    if n1 not in graph:
        graph[n1] = [n2]
    elif n2 not in graph[n1]:
        graph[n1].append(n2)

    if n2 not in graph:
        graph[n2] = [n1]
    elif n1 not in graph[n2]: 
        graph[n2].append(n1)

print(*DFS(graph, start))
print(*BFS(graph, start))
Comments