문제: https://www.acmicpc.net/problem/1260
나의 이해를 위한 상세풀이 !
다른 분의 블로그를 보며 찬찬히 이해해 나갔다.
1. 행렬 만들기
N, M, V = map(int, input().split())
# 행렬 만들기
graph = [[0]*(N+1) for _ in range(N+1)] # 정점의 개수만큼 행렬 생성
for i in range(M): # 정점간의 연결 표시하기 위해
a, b = map(int, input().split())
graph[a][b] = graph[b][a] = 1
graph를 N(정점) 개수 만큼 행렬을 생성한다.
N = 4일 때, [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
graph = 0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
정점의 개수만큼 행렬을 생성했으니까, 이제 정점 간의 연결을 1로 표시해 준다.
만약 '1 2' 가 입력된다면 정점 1과 정점 2가 연결되어 있다는 뜻이므로 0을 1로 바꿔준다.
graph[1][2] = graph[2][1] = 1
예제 입력1 처럼 1 2, 1 3, 1 4, 2 4, 3 4를 입력해 주면 그래프는 아래와 같이 된다.
graph = 0 0 0 0 0
0 0 1 1 1
0 1 0 0 1
0 1 0 0 1
0 1 1 1 0
2. 방문 리스트 만들기
# 방문 리스트 행렬
# 노드가 스택과 큐에 들어간 적이 있는지를 확인(한 번 들어갔던 노드는 다시 못 들어감)
visited1 = [0]*(N+1)
visited2 = visited1.copy()
DFS는 스택을, BFS는 큐를 사용한다. 이 때, 스택과 큐에 한 번 들어갔던 노드는 다시 방문하지 않는다.
즉, 이 노드가 스택과 큐에 들어갔다면 다시 넣지 않도록 이를 확인하는 리스트가 필요하다.
N = 4 이면 visited1 = [0, 0, 0, 0, 0]이고,
만약 1번 노드에 방문했다면 [0, 1, 0, 0, 0]이 된다.
3. DFS 함수 만들기
# DFS 함수 만들기 (재귀 이용)
def dfs(V):
visited1[V] = 1
print(V, end=' ')
for i in range(1, N+1):
if graph[V][i] == 1 and visited1[i] == 0:
dfs(i)
탐색을 시작하는 번호 1부터 탐색을 시작한다.
먼저 노드 1이 시작이므로 1을 방문 처리한다.
그러면 visited1[1] = [0, 1, 0, 0, 0]이 될 것이다. 이는 1번 노드가 스택에 들어간 적이 있다는 기록이다.
1번 노드를 방문했으므로 1번 노드를 출력한다.
print(V, end=' ')
이후 for문을 돌려서 if graph[V][i] == 1로
graph[1][1], graph[1][2], graph[1][3], graph[1][4] 를 확인한다.
위에서 행렬로 간선을 1로 표시해뒀으므로 1과 연결된 노드를 찾는다.
1과 2, 1과3, 1과 4 모두 연결돼있으므로 graph[1][2] == 1 이 모두 True가 된다.
여기서 and visited1[i] == 0 으로 2번 노드가 스택에 들어갔던 적이 있는지 확인해야 한다.
만약 2번 노드가 스택에 들어간 적이 있다면 방문리스트가 1로 되어 False가 된다.
즉, 1과 연결된 노드 중 방문 기록이 없는 노드를 찾는 코드이다.
if graph[v][i] == 1 and visited1[i] == 0:
1과 연결된 노드 중 방문 기록이 없는 노드가 있다면
dfs(i)로 재귀함수를 돌린다.
dfs(2)는 다시 위의 과정을 돌려서 2를 방문처리하고, 2와 연결된 노드를 찾는다.
이렇게 계속 연결된 노드들을 찾아 '깊이우선탐색'을 진행한다.
3. BFS 함수 만들기
# BFS 함수 만들기
def bfs(V):
queue = [V]
visited2[V] = 1 # 방문 처리
while queue:
V = queue.pop(0) # 방문 노드 제거
print(V, end = ' ')
for i in range(1, N+1):
if(graph[V][i] == 1 and visited2[i]==0):
queue.append(i)
visited2[i] = 1 # 방문 처리
탐색 시작 노드 V를 큐에 먼저 넣는다. queue = [V]
이후 방문리스트 visited2[V] = 1로 방문 처리한다.
V=1 이므로 visited2[1] = [0, 1, 0, 0, 0]이 된다.
이제 while queue:로 큐에 값이 없을 때까지(탐색이 끝날 때까지) 반복한다.
queue.pop(0)으로 0번째 요소를 돌려주고 삭제한다.
V=1 일 때,
queue = [1], visited2[1] = [0, 1, 0, 0, 0]인 상태가 되고
V = queue.pop(0)을 해주면 queue[], V = 1이 된다.
1을 꺼냈으니 1을 출력한다. print(V, end = ' ')
이후 for 문으로 연결된 노드들을 탐색한다.
원리는 dfs와 같다.
bfs 과정을 살펴보자.
V = 1
queue = [1]
visited[1] = 1 # [0, 1, 0, 0, 0]
while 문 들어가서,
queue = [], V =1 # 1 출력
for 문 들어가서,
노드 1과 2가 연결되고, 2가 방문된 적 없으므로
graph[1][2] == 1 and visited2[2] ==0 에 해당하므로
queue = [2]
visited[2] = 1로 방문 처리 # [0, 1, 1, 0, 0]
노드 1과 3이 연결되고, 3이 방문된 적 없으므로
graph[1][3] == 1 and visited2[3] ==0 에 해당하므로
queue = [2, 3]
visited[3] = 1로 방문 처리 # [0, 1, 1, 1, 0]
노드 1과 4가 연결되고, 4가 방문된 적 없으므로
graph[1][4] == 1 and visited2[4] ==0 에 해당하므로
queue = [2, 3, 4]
visited[4] = 1로 방문 처리 # [0, 1, 1, 1, 1]
모든 연결 노드 확인 후 for 문 반복 끝
queue에 값이 있으므로 while 문 탈출 안 하고 다시 반복
V = 2 이므로 2 출력
queue = [3, 4]
graph[2][1]==1 and visited[2] ==0 에 해당하지 않으므로 큐에 다시 넣지 않음.
graph[2][2], graph[2][3], graph[2][4] 도 마찬가지임
아무것도 추가되지 않고 for 문 빠져나감
V= 3 이므로 3 출력
queue = [4]
graph[3][1]==1 and visited[2] ==0 에 해당하지 않으므로 큐에 다시 넣지 않음.
graph[3][2], graph[3][3], graph[3][4] 도 마찬가지임
V= 4 이므로 4 출력
graph[4][1]==1 and visited[2] ==0 에 해당하지 않으므로 큐에 다시 넣지 않음.
graph[4][2], graph[4][3], graph[4][4] 도 마찬가지임
queue = [ ]로 while 종료
💡 최종 코드
N, M, V = map(int, input().split())
# 행렬 만들기
graph = [[0]*(N+1) for _ in range(N+1)] # 정점의 개수만큼 행렬 생성
for i in range(M): # 정점간의 연결 표시하기 위해
a, b = map(int, input().split())
graph[a][b] = graph[b][a] = 1
# 방문 리스트 행렬 (방문한 노드를 담음)
# 노드가 스택과 큐에 들어간 적이 있는지를 확인(한 번 들어갔던 노드는 다시 못 들어감)
visited1 = [0]*(N+1) # ex. [0, 0, 0, 0, 0]
visited2 = visited1.copy()
# DFS 함수 만들기 (재귀 이용)
def dfs(V):
visited1[V] = 1 # 방문 처리
print(V, end=' ') # 첫번째 노드가 방문했으므로 출력
for i in range(1, N+1):
if graph[V][i] == 1 and visited1[i] == 0:
dfs(i)
# BFS 함수 만들기
def bfs(V):
queue = [V]
visited2[V] = 1 # 방문 처리
while queue:
V = queue.pop(0) # 방문 노드 제거
print(V, end = ' ')
for i in range(1, N+1):
if(graph[V][i] == 1 and visited2[i]==0):
queue.append(i)
visited2[i] = 1 # 방문 처리
dfs(V)
print()
bfs(V)
참고 사이트:
https://velog.io/@falling_star3/백준Python-1260번-DFS와BFS
[백준][Python] 1260번 DFS와 BFS(DFS/BFS 기본 구현 자세히)
https://www.acmicpc.net/problem/1000두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.입력첫째 줄에 A와 B가 주어진다. (0 < A, B < 10)출력첫째 줄에 A+B를 출력한다.입출력 예
velog.io
'알고리즘' 카테고리의 다른 글
| 💻 [백준][파이썬] 단계별로 풀어보기 - 2차원 배열 모음(2783, 2566, 10798, 2563) (1) | 2024.12.03 |
|---|---|
| 💻 [백준-2667] python3 단지 번호 붙이기 (0) | 2024.12.02 |
| 💻 [백준 - 2606] Python3 바이러스 (2) | 2024.11.27 |
| [알고리즘] Python3 - DFS/BFS (2) | 2024.11.25 |
| 💻 [프로그래머스] Python3 코딩테스트 고득점 Kit - 스택/큐 (7) | 2024.11.20 |