https://www.acmicpc.net/problem/9466
- 그래프 이론
- 그래프 탐색
- 깊이 우선 탐색
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**6)
def dfs(x):
global ans
visited[x] = True
cycle.append(x) # 지금까지의 팀 구성
pick = arr[x]
if visited[pick]: # 이미 방문 했는가?
if pick in cycle: # cycle 내에 있는가? => cycle
idx = cycle.index(pick)
ans += cycle[idx:]
return
else:
dfs(pick)
T = int(input().strip())
for _ in range(T):
n = int(input().strip())
arr = [0] + list(map(int, input().split()))
visited = [True] + [False]*n
# 팀을 정하는 데 성공한 학생들
ans = []
for i in range(1, n+1):
if not visited[i]:
cycle = []
dfs(i)
print(n - len(ans))
코드의 자세한 설명은 아래와 같다.
ans
는 팀을 정하는 데 성공한 학생들을 저장하는 리스트로, dfs
함수를 통해 업데이트 된다.
아직 방문하지 않은 정점 i
에서 dfs
를 실행한다. 실행할 때마다, cycle
이라는 리스트를 유지한다.
cycle
은 dfs를 실행하며 방문하는 정점들을 차례로 저장하는 리스트이다.
dfs
내부에서는
인자로 들어온 x
를 방문표시하고, cycle
리스트에 x
를 삽입한다. 그 뒤, x
가 선택한 학생인 pick
을 구한다.
pick
을 방문한 적이 없다면 dfs(pick)
만약pick
을 이미 방문한 적이 있고, pick
이 cycle
내부에 있다면 cycle
내부에 처음 등장한 pick
부터 사이클을 이루고 있다는 의미이다.
(e.g.,)
입력이 아래와 같을 때 1에서 dfs를 시작하면1 -> 3 -> 3
으로 연결되는데 여기에서 팀이 되는 것(사이클)은 3 하나 뿐이다.
cycle
내부에 처음 등장한 pick
의 위치를 idx
라고 할 때, 전역변수인 ans
에 cycle[idx:]
를 이어붙인다.
마지막으로 n
에서 ans
의 개수를 뺀 값이 문제에서 원하는, 팀을 이루지 못한 학생의 수이다.