DFS는 하나의 정점에서 시작하여 그 정점의 인접한 정점 중 아직 방문하지 않은 정점이 없다면 탐색을 종료하고 있다면 방문하여 그 정점으로 부터 다시 DFS를 진행하는 재귀적인 방법으로 탐색하는 방법이며, 나중에 들어간 자료가 먼저 빠져나가는(Last In Fisrt Out) 스택(Stack)을 사용합니다.
Stack : Last In First Out
DFS는 BFS와 다르가 여러 경우의 수 중 하나를 선택하고, 선택한 상황에서 가능한 여러 경우의 수 중 또 하나를 선택하며 트리의 깊이를 넓히며 탐색하는 방법입니다.
모든 단계에서 하나의 경우의 수만 골라 탐색
STEP
스택에 시작 노드를 넣는다.
스택이 비어있으면 실행을 멈추고 False 반환.
스택의 맨 위 노드가 찾고자 하는 노드라면 탐색을 종료하고 True 반환.
3.번에서 스택의 맨 위 노드가 찾고자하는 노드가 아니라면 해당 노드를 Pop하고, 스택에 들어온 적 없는 Pop한 노드의 모든 이웃 노드를 찾아 순서대로 스택에 Push
그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.
입력
첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.
출력
첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.
파이썬 코드
방법1_인접행렬로 그래프 구현
defdfs(v):print(v, end=' ')
visit[v] = 1for i inrange(1, n + 1):
if visit[i] == 0and s[v][i] == 1:
dfs(i)
defbfs(v):
queue = [v]
visit[v] = 0while(queue):
v = queue[0]
print(v, end=' ')
del queue[0]
for i inrange(1, n + 1):
if visit[i] == 1and s[v][i] == 1:
queue.append(i)
visit[i] = 0
n, m, v = map(int, input().split())
s = [[0] * (n + 1) for i inrange(n + 1)]
visit = [0for i inrange(n + 1)]
for i inrange(m):
x, y = map(int, input().split())
s[x][y] = 1
s[y][x] = 1
dfs(v)
print()
bfs(v)
이렇게 인접행렬 방식으로 그래프를 만들어서 풀 때보다,
인접리스트로 그래프를 구현하니 훨씬 시간이 빨라졌습니다.
방법2_인접리스트로 그래프 구현
import sys
input = sys.stdin.readline
from collections import deque
defdfs(graph, v):
visited = []
stack = [v]
while stack:
n = stack.pop()
if n notin visited:
visited.append(n)
stack += reversed(graph[n])
return visited
defbfs(graph, v):
visited = []
queue = deque([v])
while queue:
n = queue.popleft()
if n notin visited:
visited.append(n)
queue += graph[n]
return visited
n, m, v = map(int, input().split())
graph = {i:[] for i inrange(1,n+1)}
for i inrange(1, m+1):
x, y = map(int, input().split())
graph[x].append(y)
graph[y].append(x)
for key in graph:
graph[key].sort()
print(' '.join(list(map(str,dfs(graph, v)))))
print(' '.join(list(map(str,bfs(graph, v)))))
계속 런타임 에러가 나서 고생했는데 ㅜㅜ
고생한 이유1.
시작노드가 어느 간선과도 연결되지 않았을경우를 고려 X 때문
처음 그래프를 초기화 할 때 입력값으로만 그래프를 만들면 안되고,
graph = {i:[] for i in range(1,n+1)} 로 모든 노드를 키값으로 초기화 해놔야 한다.
그래야 연결된 간선이 없는 노드를 만났을 때 while queue나 while stack문을 빠져나갈 수 있기 때문.
고생한 이유2.
dfs시 그래프의 밸류값(노드에 연결된 childe 노드)를 역순 정렬해주어야 한다.
난이도 1개 짜리 맞는지.. 애매한 부분이 쫌 있었다.
그리고 if n not in visited 부분의 시간은 O(N)이다. visited를 리스트로 구현했기 때문에 리스트의 요소를 탐색하는데 총 N번의 시간이 소요되기 때문이다. 그래서 visited를 딕셔너리로 구현했더니 시간이 매우 줄었습니다.
방법3_visited={} 사용
import sys
input = sys.stdin.readline
from collections import deque
defdfs(graph, v):
visited = {}
stack = [v]
while stack:
n = stack.pop()
if n notin visited:
visited.setdefault(n)
stack += reversed(graph[n])
return visited
defbfs(graph, v):
visited = {}
queue = deque([v])
while queue:
n = queue.popleft()
if n notin visited:
visited.setdefault(n)
queue += graph[n]
return visited
n, m, v = map(int, input().split())
graph = {i:[] for i inrange(1,n+1)}
for i inrange(1, m+1):
x, y = map(int, input().split())
graph[x].append(y)
graph[y].append(x)
for key in graph:
graph[key].sort()
print(' '.join(list(map(str,dfs(graph, v)))))
print(' '.join(list(map(str,bfs(graph, v)))))