오늘의 학습 키워드
그래프 탐색이란?
- 하나의 정점으로부터 시작하여 차례대로 모든 정점들을 한 번씩 방문하는 것
- Ex) 특정 도시에서 다른 도시로 갈 수 있는지 없는지, 전자 회로에서 특정 단자와 단자가 서로 연결되어 있는지
그러면 DFS란?
루트 노드(혹은 다른 임의의 노드)에서 시작해서 다음 분기(branch)로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법
탐색 순서 = 1->2->4->6->3->5->7
def dfs(graph, v, visited):
#v는 시작위치
visited[v] = True
print(v , end = ' ')
#현재 노드와 연결된 노드를 재귀적으로 호출
for i in graph[v]:
if not visited[i]:
dfs(graph, i, visited)
graph = [
[], # 0번 노드는 사용하지 않음
[2, 3, 7], # 1번 노드는 2, 3, 7번 노드와 연결
[1, 4, 6], # 2번 노드는 1, 4, 6번 노드와 연결
[1, 5, 7], # 3번 노드는 1, 5, 7번 노드와 연결
[2, 6], # 4번 노드는 2, 6번 노드와 연결
[3, 7], # 5번 노드는 3, 7번 노드와 연결
[2, 4], # 6번 노드는 2, 4번 노드와 연결
[1, 3] # 7번 노드는 1, 3번 노드와 연결
]
#각 노드가 방문한 정보를 리스트 자료형으로 표현
visited = [False] * 9
print("방문순서")
dfs(graph, 1, visited)
출력 :
방문순서
1 2 4 6 3 5 7
https://www.acmicpc.net/problem/24479
위 입출력 예시에 따르면 결론적으로 5개의 정점, 5개의 간선인데
오름차순 방문: DFS 탐색 시 인접 정점들을 오름차순으로 방문.
1. 기본 설정 및 입력 처리
import sys
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline
n, m, r = map(int, input().split()) # 정점의 수, 간선의 수, 시작 정점
graph = [[] for _ in range(n + 1)] # 인접 리스트로 그래프 표현
visited = [0] * (n + 1) # 각 정점의 방문 순서를 저장하는 리스트 (0이면 방문하지 않음)
sys.setrecursionlimit(10 ** 6)
: 재귀 깊이를 늘려 깊이 우선 탐색(DFS) 중 스택 오버플로 방지input = sys.stdin.readline
: 빠른 입력을 위해 사용, 사용하지 않으면 런타임 에러n, m, r = map(int, input().split())
: 정점의 수, 간선의 수, 시작 정점을 입력받음graph = [[] for _ in range(n + 1)]
: 그래프를 인접 리스트로 표현하기 위해 초기화visited = [0] * (n + 1)
: 각 정점이 방문된 순서를 저장할 리스트, 초기값은 02. 깊이 우선 탐색(DFS) 함수 정의
order = 1 # 방문 순서 카운터
def dfs(graph, v, visited):
global order
visited[v] = order # 방문하면 순서 기록
for i in graph[v]: # 현재 정점과 연결된 모든 정점을 순회
if visited[i] == 0: # 방문하지 않은 정점이라면
order += 1
dfs(graph, i, visited) # 재귀적으로 탐색
visited[v] = c
: 정점 v를 방문했을 때 방문 순서를 저장for i in graph[v]
: 정점 v에 연결된 모든 인접 정점을 순회if visited[i] == 0
: 아직 방문하지 않은 정점만 탐색3. 간선 정보 입력 및 그래프 구성
for i in range(m):
a, b = map(int, input().split()) # 간선 정보 입력
graph[a].append(b)
graph[b].append(a) # 무방향 그래프이므로 양쪽에 간선 추가
for i in range(m)
: m개의 간선 정보를 입력받음입력 예시에 따르면
- graph[1]에 4와 2를 추가 → graph[1] = [4, 2]
- graph[2]에 1, 3, 4를 추가 → graph[2] = [1, 3, 4]
- graph[3]에 2와 4를 추가 → graph[3] = [2, 4]
- graph[4]에 1, 2, 3을 추가 → graph[4] = [1, 2, 3]
4. 인접 리스트 정렬
for i in range(n + 1):
graph[i].sort() # 오름차순으로 인접 정점을 정렬
5. 깊이 우선 탐색 시작 및 결과 출력
dfs(graph, r, visited)
for i in range(1, n + 1):
print(visited[i])
dfs(graph, r, visited)
: 시작 정점 r에서 DFS 수행print(visited[i])
: 정점 i의 방문 순서를 출력import sys
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline
n, m, r = map(int, input().split()) # 정점의 수, 간선의 수, 시작 정점
graph = [[] for _ in range(n + 1)]
visited = [0] * (n + 1) # 방문 순서 저장. 0이면 방문 X
order = 1 # 방문 순서 변수
def dfs(graph, v, visited):
global order
visited[v] = order # 방문하면 순서 나타내기
for i in graph[v]:
if visited[i] == 0: # 방문 안 한 노드이면
order += 1
dfs(graph, i, visited) # dfs 재귀
# m개의 연결된 간선 정보 입력받기
for i in range(m):
a, b = map(int, input().split())
graph[a].append(b)
graph[b].append(a)
# 오름차순으로 인접 노드 방문하기 위해 정렬
for i in range(n + 1):
graph[i].sort()
dfs(graph, r, visited)
for i in range(1, n + 1):
print(visited[i])
🔥 dfs의 개념부터 이해하느라 시간이 오래 걸렸다. 아직 이해가 잘 안된 것 같다. 문제를 더 풀어보면서 적용해야할듯? bfs와 비교하면서도 풀어봐야 될 것 같다.
🔥 런타임에러가 나지않기 위에 하는 sys 설정, append 함수에 대해서 몰라 찾아보았다. 아직 혼자 풀기 어려운 점이 많다.
참고 문헌
[파이썬 알고리즘] 쉽게 이해하는 DFS 알고리즘 (정의, 특징, 코드)
[알고리즘] 깊이 우선 탐색(DFS)이란
[알고리즘] 너비 우선 탐색(BFS)이란