🧩 Problem Solving/[λ°±μ€€]

[λ°±μ€€] 9466 ν…€ ν”„λ‘œμ νŠΈ (python 파이썬)

μ œλ΄‰μ•„ 2022. 7. 31. 03:43

https://www.acmicpc.net/problem/9466

 

9466번: ν…€ ν”„λ‘œμ νŠΈ

이번 가을학기에 '문제 ν•΄κ²°' κ°•μ˜λ₯Ό μ‹ μ²­ν•œ 학생듀은 ν…€ ν”„λ‘œμ νŠΈλ₯Ό μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€. ν”„λ‘œμ νŠΈ νŒ€μ› μˆ˜μ—λŠ” μ œν•œμ΄ μ—†λ‹€. 심지어 λͺ¨λ“  학생듀이 λ™μΌν•œ νŒ€μ˜ νŒ€μ›μΈ κ²½μš°μ™€ κ°™μ΄ ν•œ νŒ€λ§Œ μžˆμ„

www.acmicpc.net


μ‹œκ°„μ œν•œ 3초둜 맀우 κΈΈμ§€λ§Œ λ„ˆλ¬΄ λ³΅μž‘ν•˜μ§€ μ•Šμ€ 문제.

μ•„λ§ˆ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ μ—¬λŸ¬ κ°œλΌμ„œ μ‹œκ°„μ œν•œμ„ λ„λ„ν•˜κ²Œ λ‘” κ±° κ°™λ‹€. 

 


아이디어

1. κ·Έλž˜ν”„

  • 일단 보자마자 κ·Έλž˜ν”„λ₯Ό 써야 ν•œλ‹€κ³  μƒκ°ν–ˆλ‹€.
  • 문제 μ‘°κ±΄μ—μ„œ νŒ€μ΄ 되렀면 μ„œλ‘œκ°€ 꼬리λ₯Ό λ¬Όλ“― 사이클이 생겨야 ν•œλ‹€.
  • 그럼 이 λ¬Έμ œλŠ” κ·Έλž˜ν”„μ—μ„œ '사이클을 μ–΄λ–»κ²Œ μ°Ύκ³  νŒλ³„ν•˜λƒ'에 λŒ€ν•΄μ„œ μƒκ°ν•˜λ©΄ λœλ‹€.

2. dfs

  • λ°©λ¬Έ 유무λ₯Ό 톡해 사이클이 μƒκ²ΌλŠ”μ§€ μ•ˆ μƒκ²ΌλŠ”μ§€ 찾기둜 κ²°μ •
  • 문제 μ˜ˆμ œμ— μžˆλŠ” 걸둜 μ„€λͺ…ν•˜λ©΄ ν•¨μˆ˜(dfs)μ—μ„œ 4 -> 7 -> 6 λ°©λ¬Έ ν›„ λ‹€μ‹œ 4둜 λ°©λ¬Έν•œλ‹€.
  • μ΄λ•Œ dfs(4)μ—μ„œ 이미 4κ°€ λ°©λ¬Έλ˜μ—ˆμœΌλ©΄ 사이클이라고 νŒλ‹¨ν•˜κ³  학생 수λ₯Ό 계산해쀀닀.

 


전체 μ½”λ“œ

import sys

sys.setrecursionlimit(10**6)

def dfs(n):
    global count

    visited[n] = True
    cycle_list.append(n)

    if visited[arr[n]] == True:
        if arr[n] in cycle_list:
            count -= len(cycle_list[cycle_list.index(arr[n]):])
        return

    else:
        dfs(arr[n])

T = int(input())

for _ in range(T):
    N = int(input())

    arr = [0]
    arr.extend([int(x) for x in sys.stdin.readline().rstrip().split()])

    visited = [False] * (N + 1)
    count = N
    for i in range(1, N + 1):
        if not visited[i]:
            cycle_list = []
            dfs(i)

    print(count)

 


μ½”λ“œ μ„€λͺ…

T = int(input())

for _ in range(T):
    N = int(input())

    arr = [0]
    arr.extend([int(x) for x in sys.stdin.readline().rstrip().split()])

    visited = [False] * (N + 1)
    count = N
    for i in range(1, N + 1):
        if not visited[i]:
            cycle_list = []
            dfs(i)

    print(count)

 

μž…λ ₯ν•˜λŠ” 뢀뢄은 κ°„λ‹¨ν•˜λ‹€.

arrλ¦¬μŠ€νŠΈμ—μ„œ μΈλ±μŠ€λŠ” μ„ νƒν•˜λŠ” 학생 그리고 값은 μ„ νƒλ˜λŠ” ν•™μƒμœΌλ‘œ μ €μž₯ν•œλ‹€.

dfsλŠ” 1λΆ€ν„° NκΉŒμ§€ μ „λΆ€ μ‹€ν–‰ν•˜κ³ , 이미 방문된(visited) λ…Έλ“œλŠ” λ„˜κΈ΄λ‹€.

μ™œλƒ, 이미 찾은 사이클을 μ€‘λ³΅ν•΄μ„œ 또 찾을 수 있기 λ•Œλ¬Έ.

 

def dfs(n):
    global count

    visited[n] = True
    cycle_list.append(n)

    if visited[arr[n]] == True:
        if arr[n] in cycle_list:
            count -= len(cycle_list[cycle_list.index(arr[n]):])
        return

    else:
        dfs(arr[n])

λ¨Όμ € dfsν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜λ©΄ λ°©λ¬Έ ν‘œμ‹œλ₯Ό ν•˜κ³  μž„μ‹œλ‘œ λ§Œλ“  사이클 λ¦¬μŠ€νŠΈμ— λ…Έλ“œλ₯Ό μΆ”κ°€ν•΄μ€€λ‹€.

 

그리고 λ‚΄κ°€ λ°©λ¬Έν•  λ‹€μŒ λ…Έλ“œ(arr[n])κ°€ ν•œ λ²ˆλ„ 방문을 μ•ˆ ν–ˆμœΌλ©΄ dfs(arr[n]) μ‹€ν–‰ν•΄μ€€λ‹€.

λ°˜λŒ€λ‘œ arr[n]κ°€ 이미 λ°©λ¬Έν•œ μƒνƒœλΌλ©΄  arr[n]이 사이클 λ¦¬μŠ€νŠΈμ— μžˆλŠ”μ§€ ν™•μΈν•œλ‹€.

사이클 λ¦¬μŠ€νŠΈμ— μžˆλ‹€λ©΄ 전체 ν•™μƒμˆ˜μ—μ„œ 사이클 크기만큼 λΉΌμ£Όλ©΄ λœλ‹€.

 

사이클 리슀트λ₯Ό μŠ¬λΌμ΄μ‹±ν•˜λŠ” μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™λ‹€. 

예λ₯Ό λ“€μ–΄ μœ„μ™€ 같은 κ·Έλž˜ν”„κ°€ μžˆλ‹€κ³  ν–ˆμ„ λ•Œ,

dfs(2)λ₯Ό μ‹€ν–‰ν•˜λ©΄ 사이클 λ¦¬μŠ€νŠΈμ— [2, 4, 7, 6] μ΄λ ‡κ²Œ μ €μž₯될 것이닀.

μ—¬κΈ°μ„œ 사이클은 4 7 6 μ΄λ―€λ‘œ 사이클이 μ‹œμž‘ν•œ 4μ—μ„œλΆ€ν„° 리슀트λ₯Ό 잘라주면 λœλ‹€.