Note
DFS(깊이 우선 탐색)와 BFS(너비 우선 탐색)를 함께 구현하는 문제입니다.
문제
그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.
문제 링크: https://www.acmicpc.net/problem/1260
입력
첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.
출력
첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.
예제
예제 입력 1:
4 5 1
1 2
1 3
1 4
2 4
3 4
예제 출력 1:
1 2 4 3
1 2 3 4
예제 입력 2:
5 5 3
5 4
5 2
1 2
3 4
3 1
예제 출력 2:
3 1 2 5 4
3 1 4 2 5
문제 분석
이 문제는 DFS와 BFS를 모두 구현해야 하는 기본적인 그래프 탐색 문제입니다.
그래프 표현
인접 리스트 (Adjacency List) 방식으로 그래프를 표현합니다:
- 각 정점에 연결된 정점들의 리스트를 저장
- 양방향 그래프이므로 양쪽 모두에 간선을 추가
예제 입력 1의 그래프:
1: [2, 3, 4]
2: [1, 4]
3: [1, 4]
4: [1, 2, 3]
핵심 포인트
- 정점 번호 정렬: 문제 조건에 따라 “정점 번호가 작은 것을 먼저 방문”하므로 각 정점의 인접 리스트를 정렬해야 합니다.
- 양방향 그래프: 간선을 양쪽 정점 모두에 추가해야 합니다.
- 방문 배열 초기화: DFS와 BFS를 각각 실행하기 전에 방문 배열을 초기화해야 합니다.
해결 방법
- 인접 리스트로 그래프를 구성
- 각 정점의 인접 리스트를 정렬 (작은 번호 우선)
- DFS로 탐색하여 결과 출력
- 방문 배열 초기화
- BFS로 탐색하여 결과 출력
코드 구현
제공된 코드
from collections import deque
def dfs(graph, v, visited):
# 현재 노드의 방문 처리
visited[v] = True
print(v, end = ' ')
# 현재 노드와 연결된 부분을 재귀적으로 방문
for i in graph[v]:
if visited[i] == False:
dfs(graph, i, visited)
def bfs(graph, start, visited):
queue = deque([start])
visited[start] = True
# 큐가 빌때까지 반복
while queue:
v = queue.popleft()
print(v, end = ' ')
for i in graph[v]:
if not visited[i]:
queue.append(i)
visited[i] = True
n, m, v = map(int, input().split())
visited: list[bool] = [False] * (n + 1)
graph: list[list[int]] = [[] for _ in range(n + 1)]
# 그래프 추가
for _ in range(m):
start, end = map(int, input().split()) # 1 2
graph[start].append(end)
graph[end].append(start)
# 정렬. 최소 친구들만 오게
for node in graph:
node.sort()
dfs(graph, v, visited)
print("")
visited = [False] * (n + 1)
bfs(graph, v, visited)코드 분석
1. 그래프 초기화
n, m, v = map(int, input().split())
visited: list[bool] = [False] * (n + 1)
graph: list[list[int]] = [[] for _ in range(n + 1)]n: 정점의 개수m: 간선의 개수v: 시작 정점visited: 방문 여부를 저장하는 배열 (인덱스 0은 사용하지 않음)graph: 인접 리스트로 그래프를 표현
2. 그래프 구성
for _ in range(m):
start, end = map(int, input().split())
graph[start].append(end)
graph[end].append(start)- 양방향 그래프이므로 양쪽 모두에 간선을 추가
- 예:
1 2입력 시graph[1]에 2 추가,graph[2]에 1 추가
3. 정점 번호 정렬
for node in graph:
node.sort()- 중요: 문제 조건에 따라 “정점 번호가 작은 것을 먼저 방문”
- 각 정점의 인접 리스트를 정렬하여 작은 번호부터 방문하도록 보장
4. DFS 구현
def dfs(graph, v, visited):
visited[v] = True
print(v, end = ' ')
for i in graph[v]:
if visited[i] == False:
dfs(graph, i, visited)자세한 설명은 DFS 알고리즘 포스트를 참고하세요.
5. BFS 구현
def bfs(graph, start, visited):
queue = deque([start])
visited[start] = True
while queue:
v = queue.popleft()
print(v, end = ' ')
for i in graph[v]:
if not visited[i]:
queue.append(i)
visited[i] = True자세한 설명은 BFS 알고리즘 포스트를 참고하세요.
6. 방문 배열 초기화
dfs(graph, v, visited)
print("")
visited = [False] * (n + 1) # BFS를 위해 초기화
bfs(graph, v, visited)- DFS 실행 후 방문 배열을 초기화하여 BFS를 실행
- 두 탐색이 독립적으로 동작하도록 보장
개선된 코드
더 Pythonic하게 작성한다면:
from collections import deque
def dfs(graph, v, visited):
visited[v] = True
print(v, end=' ')
for neighbor in graph[v]:
if not visited[neighbor]:
dfs(graph, neighbor, visited)
def bfs(graph, start, visited):
queue = deque([start])
visited[start] = True
while queue:
v = queue.popleft()
print(v, end=' ')
for neighbor in graph[v]:
if not visited[neighbor]:
visited[neighbor] = True
queue.append(neighbor)
# 메인 코드
n, m, v = map(int, input().split())
graph = [[] for _ in range(n + 1)]
for _ in range(m):
a, b = map(int, input().split())
graph[a].append(b)
graph[b].append(a)
# 정렬
for node in graph:
node.sort()
# DFS
visited = [False] * (n + 1)
dfs(graph, v, visited)
print()
# BFS
visited = [False] * (n + 1)
bfs(graph, v, visited)시간 및 공간 복잡도
시간 복잡도
- 그래프 구성: O(M) - 간선 개수만큼
- 정렬: O(N × log(평균 차수)) - 각 정점의 인접 리스트 정렬
- DFS: O(N + M) - 모든 정점과 간선을 한 번씩 방문
- BFS: O(N + M) - 모든 정점과 간선을 한 번씩 방문
- 전체: O(N + M)
공간 복잡도
- 그래프 저장: O(N + M) - 인접 리스트
- 방문 배열: O(N)
- DFS 스택: O(N) - 최악의 경우 (선형 그래프)
- BFS 큐: O(N) - 최악의 경우
- 전체: O(N + M)
예제 동작 과정
예제 입력 1: n=4, m=5, v=1
그래프 구성:
1: [2, 3, 4]
2: [1, 4]
3: [1, 4]
4: [1, 2, 3]
DFS 탐색 (시작: 1):
1 방문 → 출력: 1
→ 2 방문 (1과 연결, 방문 안 함)
→ 출력: 2
→ 4 방문 (2와 연결, 방문 안 함)
→ 출력: 4
→ 3 방문 (4와 연결, 방문 안 함)
→ 출력: 3
→ 더 이상 방문할 정점 없음
결과: 1 2 4 3
BFS 탐색 (시작: 1):
큐: [1]
1 처리 → 출력: 1, 큐에 [2, 3, 4] 추가
큐: [2, 3, 4]
2 처리 → 출력: 2
큐: [3, 4]
3 처리 → 출력: 3
큐: [4]
4 처리 → 출력: 4
큐: []
결과: 1 2 3 4
예제 입력 2: n=5, m=5, v=3
그래프 구성:
1: [2, 3]
2: [1, 5]
3: [1, 4]
4: [3, 5]
5: [2, 4]
DFS 탐색 (시작: 3):
3 → 1 → 2 → 5 → 4
결과: 3 1 2 5 4
BFS 탐색 (시작: 3):
3 → 1, 4 → 2 → 5
결과: 3 1 4 2 5
관련 알고리즘
- DFS (깊이 우선 탐색) - DFS 알고리즘의 상세한 원리와 구현
- BFS (너비 우선 탐색) - BFS 알고리즘의 상세한 원리와 구현