[백준 9466] 텀 프로젝트 ❗

코뉴·2022년 3월 8일
0

백준🍳

목록 보기
124/149
post-custom-banner

🥚문제

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))

🧂아이디어

그래프, DFS

참고: https://claude-u.tistory.com/435

  • 보자마자 사이클을 찾아야겠다는 생각이 떠올랐던 문제
  • 다만, 방향 그래프에서 어떻게 사이클을 판별할 것인지에 대해 고민했고, 작성한 코드를 제출했을 때 시간초과/메모리초과가 번갈아 떠서 개선하는 데 시간이 걸렸다.
    • PyPy3로 제출시 메모리 초과가 발생했다.
      PyPy3가 자주 사용하는 코드를 캐싱하여 메모리를 많이 사용하는 대신 시간을 단축할 수 있다고 한다. 앞으로 알아두자.
      Python3 와 PyPy3 차이 (읽어보기)
  • 방향 그래프에서의 사이클DFS를 통해 간단하게 판별할 수 있다.
  • dfs중, 이미 방문한 정점에 다시 방문하면 사이클이 발생했다고 볼 수 있다.
  • 코드의 자세한 설명은 아래와 같다.

    • ans는 팀을 정하는 데 성공한 학생들을 저장하는 리스트로, dfs 함수를 통해 업데이트 된다.

    • 아직 방문하지 않은 정점 i에서 dfs를 실행한다. 실행할 때마다, cycle이라는 리스트를 유지한다.

    • cycle은 dfs를 실행하며 방문하는 정점들을 차례로 저장하는 리스트이다.

    • dfs내부에서는

      1. 인자로 들어온 x를 방문표시하고, cycle 리스트에 x를 삽입한다. 그 뒤, x가 선택한 학생인 pick을 구한다.

      2. pick방문한 적이 없다dfs(pick)

      3. 만약pick이미 방문한 적이 있고, pickcycle 내부에 있다면 cycle 내부에 처음 등장한 pick부터 사이클을 이루고 있다는 의미이다.

        (e.g.,)
        입력이 아래와 같을 때 1에서 dfs를 시작하면 1 -> 3 -> 3으로 연결되는데 여기에서 팀이 되는 것(사이클)은 3 하나 뿐이다.

      4. cycle 내부에 처음 등장한 pick의 위치를 idx라고 할 때, 전역변수인 anscycle[idx:]를 이어붙인다.

      5. 마지막으로 n에서 ans의 개수를 뺀 값이 문제에서 원하는, 팀을 이루지 못한 학생의 수이다.

profile
코뉴의 도딩기록
post-custom-banner

0개의 댓글