[백준][python] 1260번: DFS와 BFS
1260번: DFS와 BFS
🔥DFS/BFS 연습문제
문제
그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오.
단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고,
더 이상 방문할 수 있는 점이 없는 경우 종료한다.
정점 번호는 1번부터 N번까지이다.
입력
첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다.
다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다.
어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.
출력
첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다.
V부터 방문된 점을 순서대로 출력하면 된다.
예제
4 5 1
1 2
1 3
1 4
2 4
3 4
예제 출력
1 2 4 3
1 2 3 4
🌝 Thinking
- 입력을 간선(무방향)이 연결하는 두 번호를 준다.
- 간선이 열결하는 두 번호 👉 인접행렬 OR 인접리스트 로 만들어 주어야한다.
- 인접 행렬과 인접리스트를 이용하여 DFS/BFS를 구현한다.
❓인접행렬 은 어떻게 만들까?
n,m,v = map(int,input().split())
#우선 (노드수+1) x (노드수+1) 크기의 정사각행렬을 만든다.
graph = [[0]*(n+1) for _ in range(n+1)]
#x,y 간선이 연결한 두번호가 정사각행렬의 인덱스이고, 그 행렬의 요소가 연결상태를 나타낸다.
for i in range(m):
x,y = map(int,input().split())
graph[x][y] = 1
graph[y][x] = 1
#정사각행렬 출력해보기.
for row in graph:
print(row)
output
[0, 0, 0, 0, 0]
[0, 0, 1, 1, 1] #노드1
[0, 1, 0, 0, 1] #노드2
[0, 1, 0, 0, 1] #노드3
[0, 1, 1, 1, 0] #노드4
다음과 같이 인접행렬이 잘 만들어지는 모습을 확인할 수 있다.
간선이 연결한 두 번호가 인접행렬에서의 요소(연결성 확인요소) 의 인덱스가 된다.
인접행렬 을 이용한 나의 풀이
n,m,v = map(int,input().split()) #인접행렬을 만듬. graph = [[0]*(n+1) for _ in range(n+1)] for i in range(m): x,y = map(int,input().split()) graph[x][y] = 1 graph[y][x] = 1 #방문확인 리스트제작. visited_dfs = [False]*(n+1) visited_bfs = [False]*(n+1) #DFS 만들기 def dfs(v): visited_dfs[v] = True print(v,end=' ') #만약 그래프가 연결이되어 있고, 방문하지 않은 상태라면 ? for i in range(n+1): if graph[v][i] == 1 and not visited_dfs[i]: #위의 과정을 반복하시오. dfs(i) #BFS 만들기 from collections import deque def bfs(v): queue = deque([v]) visited_bfs[v] = True while queue: v = queue.popleft() print(v,end=' ') for i in range(n+1): if graph[v][i]==1 and not visited_bfs[i]: queue.append(i) visited_bfs[i] = True #입출력 형식 맞추기. dfs(v) print() bfs(v)
output
1 2 4 3 1 2 3 4
그림으로 확인
통과완료!!!!@@@@@
그렇다면…?
❓인접리스트를 어떻게 만들까?
n,m,v = map(int,input().split())
graph=[[] for _ in range(n+1)]
#graph[x]는 노드x를 말하고 간선으로 y와 연결되어있으므로 y를 리스트에 담는다
#graph[y] 또한 마찬가지
for i in range(m):
x,y = map(int,input().split())
graph[x].append(y)
graph[y].append(x)
print(graph)
output
[[], [2, 3, 4], [1, 4], [1, 4], [1, 2, 3]]
# 노드1 노드2 노드3 노드4
다음과 같이 인접리스트가 잘 만들어지는 모습을 확인할 수 있다.
간선으로 연결이되어 있다는건 한쪽 노드를 기준을 잡고 다른 노드와 연결되어있다는 접근
인접리스트를 이용한 나의 풀이
n,m,v = map(int,input().split())
#인접리스트 제작.
graph=[[] for _ in range(n+1)]
for i in range(m):
x,y = map(int,input().split())
graph[x].append(y)
graph[y].append(x)
#방문확인 리스트제작.
visited_dfs = [False]*(n+1)
visited_bfs = [False]*(n+1)
#DFS 만들기.
def dfs(v):
visited_dfs[v] = True
print(v, end=' ')
for i in graph[v]:
if not visited_dfs[i]:
dfs(i)
#BFS 만들기.
from collections import deque
def bfs(v):
queue = deque([v])
visited_bfs[v]=True
while queue:
v = queue.popleft()
print(v,end=' ')
for i in graph[v]:
if not visited[i]:
queue.append(i)
visited_bfs[i] = True
#입출력 형식 맞추기.
dfs(v)
print()
bfs(v)
output
1 2 4 3
1 2 3 4
인접리스트로도 구현 완료!
🟧인접행렬 vs 🟦인접리스트
🟧인접행렬 장점 👍
-
2차원 배열의 모든 정점들의 간선 정보가 있다.
두 정점을 연결하는 간선을 조회할 때, O(1) 시간 복잡도로 가능하다.
(인덱스로 바로 찾으면 됌)
-
정점(i)의 차수를 구할 때 인접행렬의 i번째 행의 값을 모두 더하면 된다. O(n)의 시간 복잡도를 가진다.
🟧인접행렬 단점👎
- 2차원 배열을 사용함으로 메모리 공간이 낭비된다.
- 간선의 수를 모두 알아내기 위해서는 인접행렬 전체를 확인해야 된다. O(n^2)의 시간 복잡도를 가진다.
🟦인접리스트 장점 👍
-
간선만 관리하면 되므로 메모리 공간 활용이 효율적이다.
-
모든 간선의 수를 알아내기 위해 각 정점의 헤더 노드 부터 모든 인접리스트를 탐색해야하므로 O(n+e)의 시간이 소요된다.
🟦인접리스트 단점👎
- 두정점을 연결하는 간선을 조회 하거나 정점의 차수를 알기 위해서는 정점의 인접 리스트를 탐색해야 하므로 정점의 차수만큼 시간이 필요하다. O(degree(v))
- 구현이 어렵다.
출처/참고
댓글남기기