n
: 정점 개수
m
: 간선 개수
서로 다른 m개의 간선을 입력받아 트리가 몇 개인지 세는 문제이다.
연결된 노드를 탐색하면서 트리의 특징을 이용해 트리인지 아닌지 확인해 개수를 세면 될 것 같다.
⭐️ 트리는 사이클이 없어야 한다.
이를 활용해 각 정점과 그에 연결된 정점들을 DFS로 탐색하면서 트리를 확인한다.
연결된 노드를 탐색했을 때 부모 노드 외에 이미 방문했던 노드에 한번 더 연결되어있다는 것은 사이클이 있음을 의미한다❗️
⭐️ 사이클 확인 방법
- for문으로 연결된 노드들을 확인한다.
- 방문 안한 노드가 있다면 재귀적으로 DFS를 수행한다.
- 다음 노드에 이용할 부모 노드(현재 노드)를 함께 DFS에 넣어준다.
- 방문한 노드가 있는데 부모 노드가 아니라면?
- 사이클 존재함을 의미!
- 트리가 아니라는 것을 반환
DFS 수행 →
연결 정보 입력 →
최종 시간복잡도
로 최악의 경우 로 1초 내 연산 가능하다.
while문 내에서 DFS로 트리인지 판별해 개수 세기
import sys
input = sys.stdin.readline
# DFS 구현
def dfs(v, parent):
visited[v] = 1
# 연결 노드 확인
for i in tree[v]:
if not visited[i]:
# 연결 끝까지 확인
if not dfs(i, v):
return False
# 방문한 노드인데 부모 노드 아니라면 트리 아님
elif i != parent:
return False
return True
# 케이스 번호 초기화
case = 1
# 간선 정보 입력
while True:
# n, m 입력
n, m = map(int, input().split())
# 종료 조건
if n == 0 and m == 0:
break
# 트리 저장 그래프 정의
tree = [[] for _ in range(n + 1)]
# 방문 처리 리스트 정의
visited = [0] * (n + 1)
# 간선 정보 입력
for _ in range(m):
a, b = map(int, input().split())
# 정보 저장
tree[a].append(b)
tree[b].append(a)
# 트리 개수 변수 정의
count = 0
# DFS 수행
for i in range(1, n + 1):
if not visited[i]:
if dfs(i, -1):
count += 1
# 결과 출력
if count == 0:
print(f'Case {case}: No trees.')
elif count == 1:
print(f'Case {case}: There is one tree.')
else:
print(f'Case {case}: A forest of {count} trees.')
# 테스트 케이스 수 증가
case += 1
구성 요소 | 설명 |
---|---|
노드 | 데이터의 index & value 포함 요소 |
에지 | 노드 - 노드 간 연결 관계 나타내는 선 |
루트 노드 | 트리에서 가장 상위에 존재하는 노드 |
부모 노드 | 두 노드 사이의 관계에서 상위 노드 해당 노드 |
자식 노드 | 두 노드 사이의 관계에서 하위 노드 해당 노드 |
리프 노드 | 트리에서 가장 하위에 존재하는 노드 (자식 노드 X) |
서브 트리 | 전체 트리에 속한 작은 트리 |