We will find a way, we always have.

-interstellar

Problem Solving/λ°±μ€€

[λ°±μ€€] 20560번: 맛집 탐방

Redddy 2023. 9. 1. 00:56

πŸ”ˆ 문제

μ€μˆ˜λŠ” 맛집을 νƒλ°©ν•˜λŸ¬ λ„μ‹œλ‘œ 여행을 λ– λ‚  것이닀. μ€μˆ˜κ°€ 갈 λ„μ‹œμ—λŠ” 총 $N$개의 맛집이 μžˆλ‹€.

λ„μ‹œμ—λŠ” λ§›μ§‘μ—μ„œ λ§›μ§‘μœΌλ‘œ 이동할 수 μžˆλŠ” 일방톡행 길이 $M$개 있고, 각 길의 μ€‘κ°„μ—λŠ” κΈ°λ…ν’ˆ 상점이 μžˆλ‹€. μ–΄λ–€ 길은 μΆœλ°œν•˜λŠ” 맛집과 λ„μ°©ν•˜λŠ” 맛집이 같을 μˆ˜λ„ 있으며, μ—¬λŸ¬ 길이 같은 맛집을 μ—°κ²°ν•  μˆ˜λ„ μžˆλ‹€.
μ€μˆ˜λŠ” λ„μ‹œμ˜ λ§›μ§‘μ—μ„œ 여행을 μ‹œμž‘ν•΄μ„œ, 길을 μ΄μš©ν•΄ 맛집을 νƒλ°©ν•˜λ‹€ λ„μ‹œμ˜ λ§›μ§‘μ—μ„œ 여행을 끝낼 것이닀. 여행을 μ‹œμž‘ν•œ κ³³κ³Ό 여행을 끝낸 곳이 같을 ν•„μš”λŠ” μ—†λ‹€.

λ„μ‹œλŠ” μ€μˆ˜κ°€ μ‚¬λŠ” λ§ˆμ„μ—μ„œ 멀리 λ–¨μ–΄μ Έ 있기 λ•Œλ¬Έμ—, μ€μˆ˜λŠ” ν•œ 번의 μ—¬ν–‰μ—μ„œ μ΅œλŒ€ν•œ λ§Žμ€ 맛집과 상점을 λ“€λ₯΄λ €κ³  ν•œλ‹€. 특히, μ—¬ν–‰ 쀑에 λͺ¨λ“  맛집을 λ°©λ¬Έν•˜κ±°λ‚˜ λͺ¨λ“  κΈ°λ…ν’ˆ 상점을 λ°©λ¬Έν•œλ‹€λ©΄ λ‹€μŒ μ—¬ν–‰μ—μ„œ 할인 ν˜œνƒμ„ 받을 수 있기 λ•Œλ¬Έμ— μ€μˆ˜λŠ” 이런 여행이 κ°€λŠ₯ν•œμ§€ μ•Œκ³  μ‹Άμ–΄ ν•œλ‹€. μš°λ¦¬κ°€ ν•  일은, μ€μˆ˜μ˜ μ—¬ν–‰ κ³„νšμ„ λ•λŠ” 것이닀.

 

πŸ“μž…λ ₯

첫 번째 쀄에 λ§›μ§‘μ˜ 수 $N$κ³Ό 길의 수 $M$이 곡백으둜 κ΅¬λΆ„λ˜μ–΄ 주어진닀. $(1 \leq N, M \leq 500\,000$)
두 번째 쀄뢀터 $M$쀄에 걸쳐 각 길의 정보가 주어진닀. 각 μ€„μ—λŠ” 두 수 $u$, $v$κ°€ 곡백으둜 κ΅¬λΆ„λ˜μ–΄ μ£Όμ–΄μ§€λŠ”λ°, μ΄λŠ” 맛집 $u$μ—μ„œ 맛집 $v$둜 κ°€λŠ” κΈΈμ΄λΌλŠ” 것을 μ˜λ―Έν•œλ‹€. (1≤  $u$, $v$ ≤  $N$)

 

πŸ“‘μΆœλ ₯

총 3개의 쀄을 좜λ ₯ν•œλ‹€.
첫 번째 μ€„μ—λŠ” μ€μˆ˜κ°€ $N$개의 맛집을 λͺ¨λ‘ λ°©λ¬Έν•  수 μžˆλŠ” μ—¬ν–‰ κ³„νšμ΄ μ‘΄μž¬ν•˜λ©΄ 1을, 그렇지 μ•Šλ‹€λ©΄ 0을 좜λ ₯ν•œλ‹€.
두 번째 μ€„μ—λŠ” μ€μˆ˜κ°€ $M$개의 κΈ°λ…ν’ˆ 상점을 λͺ¨λ‘ λ°©λ¬Έν•  수 μžˆλŠ” μ—¬ν–‰ κ³„νšμ΄ μ‘΄μž¬ν•˜λ©΄ 1을, 그렇지 μ•Šλ‹€λ©΄ 0을 좜λ ₯ν•œλ‹€.
μ„Έ 번째 μ€„μ—λŠ” μ€μˆ˜κ°€ $N$개의 맛집을 λͺ¨λ‘ λ°©λ¬Έν•˜λ©΄μ„œ, $M$개의 κΈ°λ…ν’ˆ 상점도 λͺ¨λ‘ λ°©λ¬Έν•  수 μžˆλŠ” μ—¬ν–‰ κ³„νšμ΄ μ‘΄μž¬ν•˜λ©΄ 1을, 그렇지 μ•Šλ‹€λ©΄ 0을 좜λ ₯ν•œλ‹€.

 

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

 

문제λ₯Ό λ‹€μ‹œ μ •λ¦¬ν•˜λ©΄ 

유ν–₯ κ·Έλž˜ν”„κ°€ 주어지고, ν•œ μ μ—μ„œ μ‹œμž‘ν•˜μ—¬ λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν•  수 μžˆλŠ” 경우, ν•œ μ μ—μ„œ μ‹œμž‘ν•˜μ—¬ λͺ¨λ“  간선을 μ§€λ‚˜κ°ˆ 수 μžˆλŠ” 경우λ₯Ό μ°ΎλŠ” 것이닀. 

μ„Έλ²ˆμ§Έμ— ꡬ해야 ν•˜λŠ” 값은 μ•žμ„œ λ§ν•œ 두 상황을 μ°Ύμ•„ λ‘˜μ˜ AND κ΄€κ³„λ‘œ μ•Œ 수 μžˆλ‹€. 

 

 

κ·Έλž˜ν”„λ₯Ό ν•œλ²ˆ λ¨Έλ¦¬μ†μœΌλ‘œ 그렀보자. 

λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν–ˆλŠ”λ°, λ°©λ¬Έν•˜μ§€ λͺ»ν•˜λŠ” 간선이 μžˆμ„κΉŒ?

μžˆλ‹€.

μ•„λž˜μ™€ 같은 상황을 μ‚΄νŽ΄λ³΄λ©΄ 1 -> 2 -> 3 순으둜 λ°©λ¬Έν•˜λ©΄ λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν•  μˆ˜λŠ” μžˆμ§€λ§Œ 1->3을 μž‡λŠ” 간선은 μ§€λ‚˜κ°€μ§€ λͺ»ν•œλ‹€. 

1 -> 2 -> 3

 

그러면 λ°˜λŒ€λ‘œ λͺ¨λ“  간선을 μ§€λ‚˜κ°”λŠ”λ°, λ°©λ¬Έν•˜μ§€ λͺ»ν•˜λŠ” λ…Έλ“œκ°€ μžˆμ„κΉŒ?

 

μ²˜μŒμ—λŠ” μ—†λ‹€κ³  μƒκ°ν•˜μ˜€λ‹€. 

λͺ¨λ“  간선을 μ§€λ‚˜κ°”λ‹€λŠ” 것은 κ·Έ 간선이 μž‡κ³  μžˆλŠ” 두 λ…Έλ“œλ₯Ό μ§€λ‚˜κ°”λ‹€λŠ” 것이고, κ·Έλ ‡κ²Œν•˜λ©΄ κ·Έλž˜ν”„μ— μžˆλŠ” λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν–ˆμ„κ±°λΌκ³  μƒκ°ν–ˆλ‹€.

 

ν•˜μ§€λ§Œ!!

λ†“μΉœ 점이 μžˆμ—ˆλ‹€.

 

κ·Έλž˜ν”„κ°€ λͺ¨λ‘ μ—°κ²°λ˜μ–΄ μžˆμ§€ μ•Šμ„ μˆ˜λ„ μžˆλ‹€λŠ” 점이닀. 

 

즉 μ•„λž˜μ™€ 같은 ν˜•νƒœμ˜ κ·Έλž˜ν”„κ°€ μž…λ ₯으둜 μ£Όμ–΄μ§ˆ 수 μžˆλ‹€. 

 

μ΄λ ‡κ²Œ λœλ‹€λ©΄ 1μ΄λ‚˜ 2μ—μ„œ μ‹œμž‘ν•˜λ©΄ λͺ¨λ“  간선은 μ§€λ‚˜κ°ˆ 수 μžˆμ§€λ§Œ, λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν•˜λŠ” 것은 λΆˆκ°€λŠ₯ν•˜λ‹€!

 

이 점을 μƒκ°ν•˜μ˜€λ‹€λ©΄ 이제 μ½”λ“œμ§œλ©΄ λœλ‹€!

 

ν’€μ΄λŠ” μš°μ„  SCCλ₯Ό λ§Œλ“€κ³  DAG κ·Έλž˜ν”„λ₯Ό μƒˆλ‘œ κ·Έλ €μ£Όμ—ˆλ‹€. 그리고 μ—¬κΈ°μ„œ μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•˜λ©΄μ„œ μœ„μƒμ •λ ¬ κ²½λ‘œκ°€ μœ μΌν•œμ§€ μ•„λ‹Œμ§€, μœ„μƒμ •λ ¬ μ‹œμž‘μ μ΄ μœ μΌν•œμ§€ μ•„λ‹Œμ§€ 등을 νŒŒμ•…ν•΄μ£Όμ—ˆλ‹€.

 

πŸ’» μ½”λ“œ

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from collections import deque
import sys
sys.setrecursionlimit(10**6)
input = sys.stdin.readline
 
def dfs(cur:int):
    global idx, num
 
    idx += 1
    d[cur] = idx
    visited[cur] = True
    stk.append(cur)
 
    parent = d[cur]
 
    for nxt in graph[cur]:
        if d[nxt] == -1:
            parent = min(parent, dfs(nxt))
        elif visited[nxt]:
            parent = min(parent, d[nxt])
    
    if d[cur] == parent:
        cnt = 0
        while True:
            node = stk.pop()
            visited[node] = False
            scc_idx[node] = num
            cnt += edges_cnt[node]
            if cur == node: break
 
        scc_node[num] = cnt
        num += 1
 
    return parent
 
def topology(dag:list[list[int]], edges:list[int]) -> list[int]:
    global first, second
    queue = deque()
    level = [0]*num
    not_one = 0
 
    for i in range(num):
        if edges[i] == 0:
            queue.append((i,0))
            if len(dag[i]) + scc_node[i] >= 1:
                not_one += 1
                if not_one > 1:
                    second = False
 
    if len(queue) != 1:
        first = False
 
    while queue:
        cur,dep = queue.popleft()
        
        if level[dep]:
            first = False
        level[dep] += 1
 
        if len(dag[cur]) > 1:
            second = False
 
        if not first and not second:
            return
 
        for nxt in dag[cur]:
            edges[nxt] -= 1
 
            if not edges[nxt]:
                queue.append((nxt, dep+1))
 
    return
 
 
n,m = map(int,input().split())
graph = [[] for _ in range(n+1)]
edges_cnt = [0]*(n+1)
for _ in range(m):
    u,v = map(int,input().split())
    edges_cnt[u] += 1
    graph[u].append(v)
 
= [-1]*(n+1)
visited = [False]*(n+1)
stk = []
idx = 0
num = 0
scc_idx = dict()
scc_node = dict()
 
for cur in range(1, n+1):
    if d[cur] == -1:
        dfs(cur)
 
dag = [[] for _ in range(num)]
edges = [0]*num
 
for cur in range(1, n+1):
    for nxt in graph[cur]:
        if scc_idx[cur] != scc_idx[nxt]:
            dag[scc_idx[cur]].append(scc_idx[nxt])
            edges[scc_idx[nxt]] += 1
 
 
first = True
second = True
 
for i in range(num):
    if len(dag[i]) != len(set(dag[i])):
        second = False
        break
topology(dag, edges)
 
print(+first, +second, +first&second, sep='\n')
cs

 

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

 

μ—΄μ‹¬νžˆ μΉ˜κ³ λ°•κ³  ν•˜μ˜€λ‹€.

 

쀑간에 λŸ°νƒ€μž„ μ—λŸ¬(Error)λŠ” λ™λ–¨μ–΄μ ΈμžˆλŠ” κ·Έλž˜ν”„κ°€ μž…λ ₯으둜 μ£Όμ–΄μ§€λŠ” 지 ν™•μΈν•˜κΈ° μœ„ν•¨μ΄μ˜€λ‹€.

 

 

πŸ”— 문제링크 

맛집 탐방

 

20560번: 맛집 탐방

첫 번째 쀄에 λ§›μ§‘μ˜ 수 $N$κ³Ό 길의 수 $M$이 곡백으둜 κ΅¬λΆ„λ˜μ–΄ 주어진닀. ($1 \leq N, M \leq 500\,000$) 두 번째 쀄뢀터 $M$쀄에 걸쳐 각 길의 정보가 주어진닀. 각 μ€„μ—λŠ” 두 수 $u$, $v$κ°€ 곡백으둜 κ΅¬λΆ„λ˜

www.acmicpc.net