Hello Ocean! 🌼

[λ°±μ€€/Python] 20040. 사이클 κ²Œμž„ λ³Έλ¬Έ

Algorithm

[λ°±μ€€/Python] 20040. 사이클 κ²Œμž„

bba_dda 2021. 10. 12. 15:44
λ°˜μ‘ν˜•

문제

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

사이클 κ²Œμž„μ€ 두 λͺ…μ˜ ν”Œλ ˆμ΄μ–΄κ°€ μ°¨λ‘€λŒ€λ‘œ λŒμ•„κ°€λ©° μ§„ν–‰ν•˜λŠ” κ²Œμž„μœΌλ‘œ, μ„  ν”Œλ ˆμ΄μ–΄κ°€ ν™€μˆ˜ 번째 μ°¨λ‘€λ₯Ό, ν›„ ν”Œλ ˆμ΄μ–΄κ°€ 짝수 번째 μ°¨λ‘€λ₯Ό μ§„ν–‰ν•œλ‹€. κ²Œμž„ μ‹œμž‘ μ‹œ 0 λΆ€ν„° n − 1 κΉŒμ§€ κ³ μœ ν•œ λ²ˆν˜Έκ°€ λΆ€μ—¬λœ 평면 μƒμ˜ 점 n κ°œκ°€ 주어지며, 이 쀑 μ–΄λŠ μ„Έ 점도 일직선 μœ„μ— 놓이지 μ•ŠλŠ”λ‹€. 맀 μ°¨λ‘€ λ§ˆλ‹€ ν”Œλ ˆμ΄μ–΄λŠ” 두 점을 μ„ νƒν•΄μ„œ 이λ₯Ό μ—°κ²°ν•˜λŠ” 선뢄을 κΈ‹λŠ”λ°, 이전에 κ·Έλ¦° 선뢄을 λ‹€μ‹œ 그을 μˆ˜λŠ” μ—†μ§€λ§Œ 이미 κ·Έλ¦° λ‹€λ₯Έ μ„ λΆ„κ³Ό κ΅μ°¨ν•˜λŠ” 것은 κ°€λŠ₯ν•˜λ‹€. κ²Œμž„μ„ μ§„ν–‰ν•˜λ‹€κ°€ 처음으둜 사이클을 μ™„μ„±ν•˜λŠ” μˆœκ°„ κ²Œμž„μ΄ μ’…λ£Œλœλ‹€. 사이클 CλŠ” ν”Œλ ˆμ΄μ–΄κ°€ κ·Έλ¦° μ„ λΆ„λ“€μ˜ λΆ€λΆ„μ§‘ν•©μœΌλ‘œ, λ‹€μŒ 쑰건을 λ§Œμ‘±ν•œλ‹€.

C에 μ†ν•œ μž„μ˜μ˜ μ„ λΆ„μ˜ ν•œ λμ μ—μ„œ μΆœλ°œν•˜μ—¬ λͺ¨λ“  선뢄을 ν•œ λ²ˆμ”©λ§Œ μ§€λ‚˜μ„œ 좜발점으둜 λ˜λŒμ•„μ˜¬ 수 μžˆλ‹€.

λ¬Έμ œλŠ” 선뢄을 μ—¬λŸ¬ 개 그리닀 보면 사이클이 μ™„μ„± λ˜μ—ˆλŠ”μ§€μ˜ μ—¬λΆ€λ₯Ό νŒλ‹¨ν•˜κΈ° μ–΄λ €μ›Œ 이미 사이클이 μ™„μ„±λ˜μ—ˆμŒμ—λ„ λΆˆκ΅¬ν•˜κ³  κ²Œμž„μ„ 계속 μ§„ν–‰ν•˜κ²Œ 될 수 μžˆλ‹€λŠ” 것이닀. 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œ κ²Œμž„μ˜ 진행 상황이 주어지면 λͺ‡ 번째 μ°¨λ‘€μ—μ„œ 사이클이 μ™„μ„±λ˜μ—ˆλŠ”μ§€, ν˜Ήμ€ 아직 κ²Œμž„μ΄ 진행 쀑인지λ₯Ό νŒλ‹¨ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜λ € ν•œλ‹€.

μž…λ ₯으둜 점의 개수 nκ³Ό m λ²ˆμ§Έ μ°¨λ‘€κΉŒμ§€μ˜ κ²Œμž„ 진행 상황이 주어지면 사이클이 μ™„μ„± λ˜μ—ˆλŠ”μ§€λ₯Ό νŒλ‹¨ν•˜κ³ , μ™„μ„±λ˜μ—ˆλ‹€λ©΄ λͺ‡ 번째 μ°¨λ‘€μ—μ„œ 처음으둜 사이클이 μ™„μ„±λœ 것인지λ₯Ό 좜λ ₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

μž…λ ₯

μž…λ ₯은 ν‘œμ€€μž…λ ₯을 μ‚¬μš©ν•œλ‹€. μž…λ ₯의 첫 번째 μ€„μ—λŠ” 점의 개수λ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ •μˆ˜ 3 ≤ n ≤ 500,000 κ³Ό μ§„ν–‰λœ μ°¨λ‘€μ˜ 수λ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ •μˆ˜ 3 ≤ m ≤ 1,000,000 이 주어진닀. κ²Œμž„μ—μ„œ μ‚¬μš©ν•˜λŠ” n개의 μ μ—λŠ” 0 λΆ€ν„° n − 1 κΉŒμ§€ κ³ μœ ν•œ λ²ˆν˜Έκ°€ λΆ€μ—¬λ˜μ–΄ 있으며, 이 쀑 μ–΄λŠ μ„Έ 점도 일직선 μœ„μ— 놓이지 μ•ŠλŠ”λ‹€. μ΄μ–΄μ§€λŠ” m κ°œμ˜ μž…λ ₯ μ€„μ—λŠ” 각각 i번째 차둀에 ν•΄λ‹Ή ν”Œλ ˆμ΄μ–΄κ°€ μ„ νƒν•œ 두 점의 λ²ˆν˜Έκ°€ 주어진닀 (1 ≤ i  m).

좜λ ₯

좜λ ₯은 ν‘œμ€€μΆœλ ₯을 μ‚¬μš©ν•œλ‹€. μž…λ ₯으둜 주어진 μΌ€μ΄μŠ€μ— λŒ€ν•΄, m λ²ˆμ§Έ μ°¨λ‘€κΉŒμ§€ κ²Œμž„μ„ μ§„ν–‰ν•œ μƒν™©μ—μ„œ 이미 κ²Œμž„μ΄ μ’…λ£Œλ˜μ—ˆλ‹€λ©΄ 사이클이 처음으둜 λ§Œλ“€μ–΄μ§„ μ°¨λ‘€μ˜ 번호λ₯Ό μ–‘μ˜ μ •μˆ˜λ‘œ 좜λ ₯ν•˜κ³ , m λ²ˆμ˜ μ°¨λ‘€λ₯Ό λͺ¨λ‘ μ²˜λ¦¬ν•œ 이후에도 μ’…λ£Œλ˜μ§€ μ•Šμ•˜λ‹€λ©΄ 0을 좜λ ₯ν•œλ‹€.

 

풀이

Union - Find μ•Œκ³ λ¦¬μ¦˜μ„ λΆ€λͺ¨λ₯Ό μ €μž₯ν•˜λŠ” λ°©μ‹μœΌλ‘œ 트리λ₯Ό μ΄μš©ν•˜μ—¬ κ΅¬ν˜„ν•˜μ˜€λ‹€. 

μΆ”κ°€λ‘œ size배열을 μ‚¬μš©ν•˜μ—¬, 두 트리λ₯Ό 머지할 λ•Œ sizeκ°€ μž‘μ€ μͺ½μ„ 큰 μͺ½ 밑에 λ‹¬μ•„μ£Όμ—ˆλ‹€. 

size[i] : i λ…Έλ“œμ˜ μžμ‹ 수

μ½”λ“œ

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
# λΆ€λͺ¨λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ°°μ—΄
parent = [i for i in range(N)]
size = [1 for i in range(N)]

def find(n):
    if (parent[n] == n):
        return n
    else:
        parent[n] = find(parent[n])
        return parent[n]
def union(a, b):
    a = find(a)
    b = find(b)
    if size[a] > size[b]: # a밑에 bλ₯Ό 달아쀀닀 = b의 λΆ€λͺ¨λ₯Ό a둜 μ„€μ •
        parent[b] = a
        size[a] += size[b]
    else: # b 밑에 aλ₯Ό 달아쀀닀 = a의 λΆ€λͺ¨λ₯Ό b둜 μ„€μ • 
        parent[a] = b
        size[b] += size[a]

sys.setrecursionlimit(10 ** 9)
isDone = False
for m in range(1,M+1):
    a, b = map(int, input().split())
    if find(a) == find(b):
        print(m)
        isDone = True
        break
    union(a,b)
if not isDone:
    print(0)

κ²°κ³Ό

μ°Έκ³ 

μ‹œκ°„μ΄ˆκ³Όμ˜ 흔적듀...

python이 μ‹œκ°„μ΄ 였래 κ±Έλ €μ„œ κ·ΈλŸ°μ§€,

μ•Œκ³ λ¦¬μ¦˜μ€ μ§„μž‘ λ™μΌν–ˆλŠ”λ° μ‹œκ°„μ„ 쀄이기 μœ„ν•΄ μžμž˜ν•œ 것듀을 μΆ”κ°€ν•΄μ•Όν–ˆλ‹€. 

 

1. sys.setrecursionlimit(10 ** 9) μΆ”κ°€

μž¬κ·€ ν•¨μˆ˜ 깊이λ₯Ό μ œν•œν•΄μ„œ μ‹œκ°„μ„ 쀄일 수 μžˆλŠ” μ½”λ“œμ΄λ‹€.

 

2. find(a) == find(b) λ₯Ό unionν•¨μˆ˜ λ‚΄μ—μ„œ ν•˜κ³ μ‹Άμ—ˆλŠ”λ°, μ‹œκ°„μ΄ˆκ³Όλ‘œ 인해 λ°–μœΌλ‘œ λΉΌμ•Όν–ˆλ‹€. 

λ°˜μ‘ν˜•