[Python] 백준 11724 : 연결 요소의 개수
문제 : https://www.acmicpc.net/problem/11724
방향 없는 그래프가 주어졌을 때, 연결 요소 (Connected Component)의 개수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주어진다.
출력
첫째 줄에 연결 요소의 개수를 출력한다.
📌 문제 탐색하기
문제부터 개념 이해까지 많은 공부와 복습이 필요했던 문제였다...
일단 문제에서 묻는 '연결 요소' 라는 개념에서부터 당황을 해버렸다. 그렇다면 연결 요소란 무엇일까?
연결 요소란?
1~6까지 모든 요소를 하나의 그래프라고 생각할 때, 아래 그림처럼 연결되지 않고 나누어져 있는 경우가 있다.
이때 나눠진 각각의 그래프를 연결 요소라고 한다. 아래 그림에서는 연결 요소가 2개인 것이다.
자 이제 뭘 구하라는 건지는 이해를 했다.
근데 이제 또 다시 든 궁금증, 그래서 그건 도대체 어떻게 구하는건데?
그렇게 또 찾아보다 보니 DFS/BFS 라는 개념을 접하게 됐다. 근데 분명 나 이거 학교 자료구조 시간에 배웠었는데...기억이 잘 안 나는 관계로 이참에 다시 정리해보려고 한다!
DFS
- Defph First Search (깊이 우선 탐색)
- 아래 그림과 같이 한 방향으로 최대한 깊이 내려간 뒤, 더이상 내려갈 곳이 없으면 옆으로 이동해서 탐색
- 주로 모든 노드를 방문하고자 할 때 사용하는 방식
- BFS보다 비교적 간단하지만, 검색 속도가 더 느리다
BFS
- Breadth First Search (너비 우선 탐색)
- 시적점인 루트 노드와 같은 거리에 있는 노드를 우선으로 방문
- 주로 최단 경로를 탐색할 때 사용
이 문제에서는 모든 경로를 확인해야 하기 때문에 dfs가 더 적합할 것 같다.
움...근데 역시 개념만으로는 코드를 어떻게 짜야할지 감이 너무나도 안 잡혀서...결국 이번만 해설 코드를 먼저 보고 공부하기로 결심했다...대신 이 기회에 dfs는 정복해야지!!!
📌 코드 설계하기
1. 입력값 가져오기
- 파이썬에서는 재귀 깊이에 대한 호출 제한이 있기 때문에, 이 제한을 풀기 위해서는 다음과 같이 가져와야 한다.
sys.setrecursionlimit(10**6)
- 첫 줄의 N,M 값 가져오기
N, M = map(int, sys.stdin.readline().split())
2. 인접 리스트 구현
- 노드 번호를 인덱스로 사용하는 2차원 인접 리스트 생성
- 1부터 N까지의 인덱스를 사용하기 위해 N+1로 범위 설정
- 양방향 간선이므로 a->b, b->a 모두 값 할당
graph = [[] for _ in range(N+1)]
for _ in range(M):
a, b = map(int, sys.stdin.readline().split())
graph[a].append(b)
graph[b].append(a)
//예시
graph = [
[], # 0번 노드 (사용하지 않음)
[2, 3], # 1번 노드와 연결된 노드: 2, 3
[1, 5], # 2번 노드와 연결된 노드: 1, 5
[1, 4], # 3번 노드와 연결된 노드: 1, 4
[3], # 4번 노드와 연결된 노드: 3
[2] # 5번 노드와 연결된 노드: 2
]
3. 탐색을 위한 배열 초기화
- 기본값은 false로 설정하고, 탐색을 하면 true로 값 변경
visited = [False for _ in range(N+1)]
4. dfs 함수 구현 (제일 중요!!!)
- node : 현재 방문 중인 노드의 번호
- node와 연결된 모든 노드를 탐색하며, 방문 시 visited[node]=True
- 현재 노드와 직접 연결된 노드들을 for문으로 순회
- 방문한 노드의 재탐색을 방지하기 위해, if now visited[x] 만 탐색
- 방문하지 않은 노드를 탐색하기 위해 dfs 함수를 재귀적으로 호출
def dfs(node):
visited[node] = True
for x in graph[node]:
if not visited[x]:
dfs(x)
5. 연결 요소 개수 구하기
- 연결 요소 개수 ans=0으로 초기화
- visited[i]가 false이면 ans값 증가
- 연결 안 된 해당 노드 기준으로 새로운 연결된 그래프 dfs로 탐색
ans = 0
for i in range(1, N+1):
if not visited[i]:
ans += 1
dfs(i)
print(ans)
📌 정답 코드
import sys
sys.setrecursionlimit(10**6)
input=sys.stdin.readline
N,M=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)
visited = [False for _ in range(N+1)]
def dfs(node) :
visited[node]=True
for x in graph[node]:
if not visited[x]:
dfs(x)
ans=0
for i in range(1,N+1):
if not visited[i]:
ans+=1
dfs(i)
print(ans)
해설 : https://whydevsaysno.notion.site/9e619ebd5e784380a61b6196715edb52