DFS/BFS

이론

자료구조(Data Structure)

데이터를 표현하고 관리하고 처리하기 위한 구조

DFS(Depth-First Search)

깊이 우선 탐색으로 그래프에서 깊은 부분을 먼저 탐색하는 알고리즘으로 Stack 자료구조를 이용한다.

  1. 탐색 시작 노드를 스택에 삽입하고 방문처리를 한다.
  2. 스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면 그 인접 노드를 스택에 넣고 방문 처리를 한다. 방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다.
  3. 2의 과정을 더 이상 수행할 수 없을 때까지 반복한다.

데이터 개수가 N개인 경우 O(N)의 시간 복잡도를 가진다.

BFS(Breadth First Search)

너비 우선 탐색으로 가까운 노드부터 탐색하는 알고리즘으로 Queue 자료구조를 이용한다.

  1. 탐색 시작 노드를 큐에 삽입하고 방문 처리를 한다.
  2. 큐에서 노드를 꺼내 해당 노드의 인접 노드 중에서 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리를 한다.
  3. 2의 과정을 더 이상 수행할 수 없을 때까지 반복한다.

데이터 개수가 N개인 경우 O(N)의 시간 복잡도를 가지며, 실제 수행 시간은 DFS보다 좋은 편이다.

실전문제


[실전문제 1] 음료수 얼려 먹기

N, M = map(int, input().split())

graph = []
for i in range(N):
    graph.append(list(map(int, input())))

# DFS로 특정한 노드를 방문한 뒤에 연결된 모든 노드들도 방문
def dfs(x,y):
    if x <= -1 or x >= N or y <= -1 or y >= N:
        return False
    if graph[x][y] == 0:
        graph[x][y] = 1
        dfs(x - 1, y)
        dfs(x, y - 1)
        dfs(x + 1, y)
        dfs(x, y + 1)
				return True
    return False

result = 0
for i in range(N):
    for j in range(M):
        if dfs(i,j) == True:
            result += 1

print(result)

[실전 문제 2] 미로 탈출

from collections import deque

# N, M을 공백으로 구분하여 입력받기
n, m = map(int, input().split())
# 2차원 리스트의 맵 정보 입력받기
graph = []
for i in range(n):
    graph.append(list(map(int, input())))

# 이동할 네 방향 정의
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

# BFS 구현
def bfs(x, y):
    # 큐 구현을 위해 deque 라이브러리 사용
    queue = deque()
    queue.append((x,y))
    # 큐가 빌 때까지 반복
    while queue:
        x, y = queue.popleft()
        # 현재 위치에서 네 방향으로 위치 확인
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx < 0 or ny < 0 or nx >= n or ny >= m:
                continue
            if graph[nx][ny] == 0:
                continue
            # 해당 노드를 처음 방문하는 경우 최단 거리 기록
            if graph[nx][ny] == 1:
                graph[nx][ny] = graph[x][y] + 1
                queue.append((nx,ny))
    # 가장 오른쪽 아래(n,m)까지 최단 거리 반환
    return graph[n-1][m-1]

print(bfs(0,0))

기출문제


[기출문제 1] 특정거리의 도시 찾기

# https://www.acmicpc.net/problem/18352

from collections import deque
import sys
input = sys.stdin.readline

N, M, K, X = map(int, input().split())

# 2차원 인접 리스트로 그래프 표현
graph = [[] for _ in range(N + 1)]
for i in range(M):
    a,b = map(int,input().split())
    graph[a].append(b)

visited = [False] * (N + 1)
distance = [0] * (N + 1)

queue = deque([X])
visited[X] = True
# 큐가 빌때까지 반복
while queue:
    v = queue.popleft()
    # 해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입
    for i in graph[v]:
        if not visited[i]:
            visited[i] = True
            distance[i] = distance[v] + 1 # bfs 이므로 최단거리
            queue.append(i)

flag = False
for i in range(1,N+1):
    if distance[i] == K:
        print(i)
        flag = True
if not flag:
    print(-1)

[기출문제 3] 경쟁적 전염

import sys
input = sys.stdin.readline

N, K = map(int, input().split())
arr = [list(map(int, input().split())) for _ in range(N)]
S, X, Y = map(int, input().split())
tmp = [x[:] for x in arr]

def spread(x,y):
    direct = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    for i in range(4):
        dx = x + direct[i][0]
        dy = y + direct[i][1]
        if 0 <= dx < N and 0 <= dy < N and not arr[dx][dy] and (not tmp[dx][dy] or tmp[dx][dy] > arr[x][y]):
            tmp[dx][dy] = arr[x][y]

flag = False
for s in range(S):
    for i in range(N):
        for j in range(N):
            if arr[i][j] != 0:
                spread(i, j)
    arr = [x[:] for x in tmp]
    if arr[X - 1][Y - 1]:
        print(arr[X - 1][Y - 1])
        flag = True
        break
if not flag:
    print(arr[X - 1][Y - 1])

[기출문제 2] 연구소

# https://www.acmicpc.net/problem/14502
# python3로 제출 시, 시간초과 -> bfs 로 고처야 한다고 한다. (함수호출이 느려서)
# pypy3오 제출 시, 성공!

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
arr = [list(map(int, input().split())) for _ in range(N)]
answer = []

def spread_virus(x, y):
    direct = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    for i in range(4):
        nx = x + direct[i][0]
        ny = y + direct[i][1]
        if 0 <= nx < N and 0 <= ny < M and not tmp[nx][ny]:
            tmp[nx][ny] = 2
            spread_virus(nx, ny)

def dfs(wall):
    global tmp
    if wall == 3:
        tmp = [x[:] for x in arr]
        for i in range(N):
            for j in range(M):
                if tmp[i][j] == 2:
                    spread_virus(i, j)
        answer.append(sum([x.count(0) for x in tmp]))
        return
    for i in range(N):
        for j in range(M):
            if arr[i][j] == 0:
                arr[i][j] = 1
                dfs(wall + 1)
                arr[i][j] = 0
dfs(0)
print(max(answer))