We will find a way, we always have.

-interstellar

Problem Solving/λ°±μ€€

[λ°±μ€€] 17398번: 톡신망 λΆ„ν• 

Redddy 2023. 7. 2. 20:03

πŸ”ˆ 문제

BOJ의 μΈκΈ°μŠ€νƒ€, 방솑인 κΆŒμš±μ œλŠ” 톡신 νšŒμ‚¬μ— μ·¨μ—…ν–ˆλ‹€. ν˜„μž¬ 이 톡신 νšŒμ‚¬λŠ” λ„ˆλ¬΄λ‚˜ 큰 톡신망을 ν•œ μ§€μ‚¬μ—μ„œ κ΄€λ¦¬ν•˜λŠλΌ 큰 λΉ„μš©μ„ μ§€λΆˆν•˜κ³  μžˆμ—ˆλ‹€. κ·Έλž˜μ„œ νšŒμ‚¬λŠ” 졜근 IT의 νŠΈλ Œλ“œ 쀑 ν•˜λ‚˜μΈ 'νƒˆμ€‘μ•™ν™”'에 νŽΈμŠΉν•˜μ—¬, 톡신망을 λΆ„ν• ν•˜λ„λ‘ κ²°μ •ν–ˆλ‹€. κ·Έλž˜μ„œ μš±μ œν•œν…Œ 톡신망을 λΆ„ν•  ν• λ•Œ λ°œμƒν•˜λŠ” λΉ„μš©μ„ λΆ„μ„ν•˜λ„λ‘ μ§€μ‹œν–ˆλ‹€.
ν˜„μž¬ νšŒμ‚¬ λ§μ—λŠ” 1λ²ˆλΆ€ν„° Nλ²ˆκΉŒμ§€ 총 N개의 톡신 탑이 μ‘΄μž¬ν•˜λ©°, 톡신탑 κ°„μ˜ 연결이 M개 μ‘΄μž¬ν•œλ‹€. μ΄λ•Œ νšŒμ‚¬μ—μ„œλŠ” 총 Q번 톡신탑 κ°„μ˜ 연결을 μ œκ±°ν•¨μœΌλ‘œμ¨ ν•˜λ‚˜μ˜ 톡신망을 μ—¬λŸ¬ 개의 ν†΅μ‹ λ§μœΌλ‘œ λΆ„λ¦¬ν•˜λ €κ³  ν•œλ‹€. ν†΅μ‹ λ§μ΄λž€, ν†΅μ‹ νƒ‘μ˜ 연결을 톡해 도달 κ°€λŠ₯ν•œ ν†΅μ‹ νƒ‘λ“€μ˜ 집합이닀. 톡신탑 κ°„μ˜ μ—°κ²° 관계λ₯Ό μ œκ±°ν•  λ•Œ λ“œλŠ” λΉ„μš©μ€ μ œκ±°ν•œ ν›„ 톡신망이 두 개둜 λ‚˜λˆ„μ–΄μ§„λ‹€λ©΄ λ‚˜λˆ μ§„ 두 개의 톡신망에 μ†ν•œ ν†΅μ‹ νƒ‘λ“€μ˜ 갯수의 곱이 되며, λ‚˜λˆ„μ–΄μ§€μ§€ μ•Šμ„ 경우 0이닀.

 

<κ·Έλ¦Ό 1>

κ·Έλ¦Ό 1을 μ˜ˆμ‹œλ‘œ ν• λ•Œ, μ—°κ²° (3, 4)λ₯Ό μ œκ±°ν•˜λ©΄ {1, 2, 3}, {4, 5, 6}으둜 λΆ„ν•  되며, μ΄λ•Œ λ°œμƒν•˜λŠ” λΉ„μš©μ€ 3 × 3 = 9κ°€ λœλ‹€. λŒ€μ‹  μ—°κ²° (2, 3)을 μ œκ±°ν•˜λ©΄, 망이 λ‚˜λˆ μ§€μ§€ μ•Šμ•˜κΈ°μ— λΉ„μš©μ€ 0이 λœλ‹€.
μš±μ œλŠ” νšŒμ‚¬μ˜ μš”μ²­μ— 따라 Q번의 제거λ₯Ό 톡해 λ‚˜μ˜€λŠ” λΉ„μš©μ˜ 합을 ꡬ해야 ν•œλ‹€. ν•˜μ§€λ§Œ μš±μ œλŠ” νšŒμ‚¬μ˜ 톡신망을 μ΄μš©ν•΄ λ°©μ†‘ν•˜κΈ° λ°”μ˜κΈ° λ•Œλ¬Έμ— μš°λ¦¬κ°€ λ„μ™€μ£Όμž.

 

πŸ“μž…λ ₯

첫 번째 μ€„μ—λŠ” ν†΅μ‹ νƒ‘μ˜ 개수인 μžμ—°μˆ˜ N, 톡신탑 μ‚¬μ΄μ˜ μ—°κ²°μ˜ 개수인 μžμ—°μˆ˜ M, 톡신망 μ—°κ²° λΆ„ν•  횟수인 μžμ—°μˆ˜ Qκ°€ 곡백으둜 κ΅¬λΆ„λ˜μ–΄ 주어진닀. (1 ≤ N ≤ 100,000, 1 ≤ M ≤ 100,000, 1 ≤ Q ≤ M)
두 번째 쀄뢀터 M개의 쀄에 걸쳐 두 개의 μžμ—°μˆ˜ X, Yκ°€ 곡백으둜 κ΅¬λΆ„λ˜μ–΄ 주어진닀. μ΄λŠ” X ν†΅μ‹ νƒ‘κ³Ό Y ν†΅μ‹ νƒ‘ 사이에 연결이 μžˆμŒμ„ λœ»ν•œλ‹€. (1 ≤ X, Y ≤ N, X ≠ Y)

μ€‘λ³΅λœ 연결은 주어지지 μ•ŠμœΌλ©°, λͺ¨λ“  톡신탑은 μ²˜μŒμ—” ν•˜λ‚˜μ˜ 톡신망에 μ†ν•œλ‹€. 쑰건에 μ˜ν•΄ 자기 μžμ‹ κ³Ό 연결이 μžˆλŠ” 톡신탑은 μ—†λ‹€.

κ·Έ λ‹€μŒ 쀄뢀터 Q개의 쀄에 걸쳐 제거될 μ—°κ²°μ˜ 번호인 μžμ—°μˆ˜ Aκ°€ 주어진닀. μ΄λŠ” A번째둜 μž…λ ₯된 (X, Y)의 연결이 μ œκ±°λ˜μ—ˆμŒμ„ μ˜λ―Έν•œλ‹€. (1 ≤ A ≤ M)
이미 제거된 연결은 λ‹€μ‹œ μ œκ±°λ˜μ§€ μ•ŠμœΌλ©°, μ œκ±°λŠ” μž…λ ₯ μˆœμ„œλŒ€λ‘œ μ§„ν–‰λœλ‹€.

 

πŸ“‘μΆœλ ₯

첫 번째 쀄에 Q개의 연결을 μˆœμ„œλŒ€λ‘œ μ œκ±°ν•˜λŠ”λ° λ“œλŠ” λΉ„μš©μ˜ 합을 좜λ ₯ν•œλ‹€.

 

πŸ“š λ¬Έμ œ ν’€μ΄

 

λ¬Έμ œκ°€ μž¬λ°Œμ–΄μ„œ μ˜€λžœλ§Œμ— 풀이글을 μž‘μ„±ν•œλ‹€.

 

μœ λ‹ˆμ˜¨ νŒŒμΈλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ μ‰½κ²Œ 간선을 μ—°κ²°ν•˜λŠ” 방법은 λ°°μ› μ§€λ§Œ, λ°˜λŒ€λ‘œ 간선을 μ œκ±°ν•˜λŠ” 방법은 생각해본적이 μ—†μ—ˆλ‹€. 

이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ κ³ λ―Όν•΄λ³΄μ•˜λŠ”λ°, 각 κ°„μ„ μ œκ±°λ§ˆλ‹€ 제거된 κ°„μ„  말고 λ‹€λ₯Έ 경둜λ₯Ό ν†΅ν•΄μ„œ 이동이 κ°€λŠ₯ν•œμ§€ 탐색을 ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— μ‹œκ°„ λ³΅μž‘λ„ $O(V+E)$ 을 $Q$ 번 μˆ˜ν–‰ν•˜λ―€λ‘œ μ‹œκ°„μ΄ˆκ³Όκ°€ λ°œμƒν•œλ‹€.

 

ν•˜μ§€λ§Œ 간선을 μ œκ±°ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ—°κ²°ν•˜λŠ” κ²ƒμœΌλ‘œλ„ 이 λ¬Έμ œλŠ” ν•΄κ²° κ°€λŠ₯ν•˜λ‹€. 

 

Q개의 μ—°κ²°λœ 간선을 μ§€μš°λŠ”λ°, λ‹€μ‹œ λ§ν•˜λ©΄ M - Q 의 간선은 μ§€μ›Œμ§€μ§€ μ•ŠλŠ”λ‹€. μž…λ ₯된 Q개의 간선을 μ œμ™Έν•˜κ³  M - Q개의 간선을 이어쀀닀.

 

ν˜„μž¬ μƒνƒœλŠ” Q개의 간선을 λͺ¨λ‘ μ§€μš°κ³  λ‚œ λ’€μ˜ κ·Έλž˜ν”„μ΄λ‹€. 

 

μ§€μ›Œμ•Ό ν•˜λŠ” Q개의 κ°„μ„  쀑 제일 λ§ˆμ§€λ§‰ κ°„μ„  $X$ 에 μ˜ν•΄ μ—°κ²°λ˜μ–΄ μžˆλŠ” A와 B의 λΆ€λͺ¨κ°€ κ°™λ‹€λ©΄ κ°„μ„  $X$λ₯Ό μ§€μ›Œλ„ 이 λ‘˜μ€ μ—°κ²°λ˜μ–΄ μžˆλ‹€λŠ” λœ»μ΄λ‹€. λ°˜λŒ€λ‘œ λΆ€λͺ¨κ°€ λ‹€λ₯΄λ‹€λ©΄ $X$κ°€ 제거됨으둜써 λ‘˜μ΄ λ‚˜λˆ μ‘Œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.  

 

이 점을 μ΄μš©ν•˜μ—¬ Q개의 간선을 μ—°κ²°ν•˜λŠ” μž‘μ—…μ„ 거꾸둜 μ§„ν–‰ν•œλ‹€. 

 

각각의 λ…Έλ“œλ§ˆλ‹€ μ—°κ²°λ˜μ–΄ μžˆλŠ” λ…Έλ“œμ˜ κ°―μˆ˜λ„ λ”°λ‘œ μ €μž₯ν•œλ‹€.

 

πŸ’» μ½”λ“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from sys import stdin
input = stdin.readline
 
def find(x:int, parent:list[int]) -> int:
    if x != parent[x]:
        parent[x] = find(parent[x], parent)
    return parent[x]
 
def union(a:int, b:int, parent:list[int]) -> None:
    a = find(a, parent)
    b = find(b, parent)
 
    if a < b:
        parent[b] = a
        cost[a] += cost[b]
    elif a > b:
        parent[a] = b
        cost[b] += cost[a]
 
n,m,q = map(int,input().split())
graph = [[] for _ in range(n+1)]
tree = []
edges = [tuple(map(int,input().split())) for _ in range(m)]
 
tmp = [False]*m
cut = []
 
parent = [i for i in range(n+1)]
cost = [1 for _ in range(n+1)]
 
for _ in range(q):
    k = int(input())-1
    cut.append(k)
    tmp[k] = True
 
for i in range(m):
    if not tmp[i]:
        x,y = edges[i]
        if find(x, parent) != find(y, parent):
            union(x,y,parent)
 
ans = 0
 
for i in range(q-1-1-1):
    x,y = edges[cut[i]]
    if find(x, parent) != find(y, parent): # λ‘˜μ˜ λΆ€λͺ¨κ°€ λ‹€λ₯΄λ‹€λ©΄ μ΄κ±΄ μ΄μ–΄μ‘Œλ˜κ²ƒ
        ans += cost[find(x, parent)] * cost[find(y, parent)]
        union(x,y,parent)
 
print(ans)
cs

 

🍭 μ‹œν–‰μ°©μ˜€

 

첫번째 ν‹€λ Έλ˜ μ΄μœ λŠ” 각각 λ…Έλ“œλ§ˆλ‹€ μ—°κ²°λ˜μ–΄ μžˆλŠ” λ…Έλ“œμ˜ 수λ₯Ό 확인할 λ•Œ μ‹€μˆ˜κ°€ μžˆμ—ˆλ‹€. 

 

πŸ”— 문제링크 톡신망 λΆ„ν• 

 

17398번: 톡신망 λΆ„ν• 

첫 번째 μ€„μ—λŠ” ν†΅μ‹ νƒ‘μ˜ 개수인 μžμ—°μˆ˜ N, 톡신탑 μ‚¬μ΄μ˜ μ—°κ²°μ˜ 개수인 μžμ—°μˆ˜ M, 톡신망 μ—°κ²° λΆ„ν•  횟수인 μžμ—°μˆ˜ Qκ°€ 곡백으둜 κ΅¬λΆ„λ˜μ–΄ 주어진닀. (1 ≤ N ≤ 100,000, 1 ≤ M ≤ 100,000, 1 ≤ Q 

www.acmicpc.net