파이썬 μ•Œκ³ λ¦¬μ¦˜

[μ΄μ½”ν…Œ Ch10-4] 컀리큘럼 (Graph)

은진 2022. 3. 1. 22:12

πŸ‘©πŸ»β€πŸ’»λ¬Έμ œμ„€λͺ…

[μ΄μ½”ν…Œ Ch10-4] 컀리큘럼 (Graph)
μ΄μ½”ν…Œ

λ™λΉˆμ΄λŠ” 온라인으둜 컴퓨터 곡학 κ°•μ˜λ₯Ό λ“£κ³  μžˆλ‹€. 이 λ•Œ 각 온라인 κ°•μ˜λŠ” μ„ μˆ˜ κ°•μ˜κ°€ μžˆμ„ 수 μžˆλŠ”λ°, μ„ μˆ˜ κ°•μ˜κ°€ μžˆλŠ” κ°•μ˜λŠ” μ„ μˆ˜ κ°•μ˜λ₯Ό λ¨Όμ € λ“€μ–΄μ•Όλ§Œ ν•΄λ‹Ή κ°•μ˜λ₯Ό 듀을 수 μžˆλ‹€. λ™λΉˆμ΄λŠ” 총 N개의 κ°•μ˜λ₯Ό λ“£κ³ μž ν•œλ‹€. κ°•μ˜λŠ” 1λ²ˆλΆ€ν„° Nλ²ˆκΉŒμ§€μ˜ 번호λ₯Ό 가진닀. λ˜ν•œ λ™μ‹œμ— μ—¬λŸ¬ 개의 κ°•μ˜λ₯Ό 듀을 수 μžˆλ‹€κ³  κ°€μ •ν•œλ‹€. 예λ₯Ό λ“€μ–΄, N = 3일 λ•Œ, 3번 κ°•μ˜μ˜ μ„ μˆ˜ κ°•μ˜λ‘œ 1번과 2번 κ°•μ˜κ°€ 이씨고, 1번과 2번 κ°•μ˜λŠ” μ„ μˆ˜ κ°•μ˜κ°€ μ—†λ‹€κ³  ν•˜μž. 그리고 각 κ°•μ˜μ— λŒ€ν•˜μ—¬ κ°•μ˜ μ‹œκ°„μ΄ λ‹€μŒκ³Ό κ°™λ‹€κ³  ν•˜μž.


1번 κ°•μ˜: 30μ‹œκ°„
2번 κ°•μ˜: 20μ‹œκ°„
3번 κ°•μ˜: 40μ‹œκ°„


이 경우, 1번 κ°•μ˜λ₯Ό μˆ˜κ°•ν•˜κΈ°κΉŒμ§€μ˜ μ΅œμ†Œ μ‹œκ°„μ€ 30μ‹œκ°„, 2번 κ°•μ˜λ₯Ό μˆ˜κ°•ν•˜κΈ°κΉŒμ§€λŠ” μ΅œμ†Œ 20μ‹œκ°„, 3번 κ°•μ˜λ₯Ό μˆ˜κ°•ν•˜κΈ°κΉŒμ§€λŠ” μ΅œμ†Œ 70μ‹œκ°„μ΄ ν•„μš”ν•˜λ‹€. λ™λΉˆμ΄κ°€ λ“£κ³ μž ν•˜λŠ” N개의 κ°•μ˜ 정보가 μ£Όμ–΄μ‘Œμ„ λ•Œ, N개의 κ°•μ˜μ— λŒ€ν•˜μ—¬ μˆ˜κ°•ν•˜κΈ°κΉŒμ§€λŠ” κ±Έλ¦¬λŠ” μ΅œμ†Œ μ‹œκ°„μ„ 좜λ ₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•΄λΌ.


μž…λ ₯쑰건

  • 첫째쀄에 λ™λΉˆμ΄κ°€ λ“£κ³ μž ν•˜λŠ” κ°•μ˜μ˜ 수 N(1 <= N <= 500)이 주어진닀.
  • λ‹€μŒ N개의 μ€„μ—λŠ” 각 κ°•μ˜μ˜ κ°•μ˜μ‹œκ°„κ³Ό κ·Έ κ°•μ˜λ₯Ό λ“£κΈ° μœ„ν•΄ λ¨Όμ € λ“€μ–΄μ•Ό ν•˜λŠ” κ°•μ˜λ“€μ˜ λ²ˆν˜Έκ°€ μžμ—°μˆ˜λ‘œ 주어지며, 각 μžμ—°μˆ˜λŠ” 곡백으둜 κ΅¬λΆ„λœλ‹€. 이 λ•Œ κ°•μ˜ μ‹œκ°„μ€ 100,000 μ΄ν•˜μ˜ μžμ—°μˆ˜μ΄λ‹€.
  • 각 κ°•μ˜ λ²ˆν˜ΈλŠ” 1λΆ€ν„° NκΉŒμ§€λ‘œ κ΅¬μ„±λ˜λ©°, 각 쀄은 -1둜 λλ‚œλ‹€.

좜λ ₯쑰건

  • N개의 κ°•μ˜μ— λŒ€ν•΄ μˆ˜κ°•ν•˜κΈ°κΉŒμ§€ κ±Έλ¦¬λŠ” μ΅œμ†Œ μ‹œκ°„μ„ ν•œ 쀄에 ν•˜λ‚˜μ”© 좜λ ₯ν•œλ‹€.


μž…λ ₯ μ˜ˆμ‹œ

5
10 -1
10 1 -1
4 1 -1
4 3 1 -1
3 3 -1

좜λ ₯ μ˜ˆμ‹œ

10
20
14
18
17


✍️Idea Sketch

μ•Œκ³ λ¦¬μ¦˜ : μœ„μƒ μ •λ ¬

λ¬Έμ œμ—μ„œ "μ„ μˆ˜ κ°•μ˜κ°€ μžˆλŠ” κ°•μ˜λŠ” μ„ μˆ˜ κ°•μ˜λ₯Ό λ¨Όμ € λ“€μ–΄μ•Όλ§Œ ν•΄λ‹Ή κ°•μ˜λ₯Ό 듀을 수 μžˆλ‹€. " λŠ” λ¬Έμž₯μ—μ„œ 눈치챌 수 μžˆλ‹€. μœ„μƒ 정렬은 μˆœμ„œκ°€ μ •ν•΄μ Έ μžˆλŠ” 일련의 μž‘μ—…μ„ μ°¨λ‘€λŒ€λ‘œ μˆ˜ν–‰ν•΄μ•Όν•  λ•Œ μ‚¬μš©ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. λ°©ν–₯ κ·Έλž˜ν”„μ˜ λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©ν–₯성에 거슀λ₯΄μ§€ μ•Šλ„λ‘ μˆœμ„œλŒ€λ‘œ λ‚˜μ—΄ν•˜λŠ” μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€.


μ‹œκ°„λ³΅μž‘λ„

O(V + E)

μœ„μƒ μ •λ ¬μ˜ μ‹œκ°„λ³΅μž‘λ„λŠ” O(V + E)이닀. μœ„μƒ 정렬을 μˆ˜ν–‰ν•  λ•ŒλŠ” λͺ¨λ“  λ…Έλ“œλ₯Ό νƒμƒ‰ν•œλ‹€. 그리고 ν•œ λ…Έλ“œλ₯Ό 탐색할 λ•Œλ§ˆλ‹€ ν•΄λ‹Ή λ…Έλ“œμ—μ„œ μΆœλ°œν•˜λŠ” 간선을 νƒμƒ‰ν•œλ‹€. (λ°©ν–₯을 거슀λ₯΄μ§€ μ•ŠλŠ”λ‹€) 결과적으둜 λͺ¨λ“  λ…Έλ“œμ™€ 간선을 ν™•μΈν•˜λ―€λ‘œ O(V + E)의 μ‹œκ°„μ΄ μ†Œμš”λœλ‹€.


βœοΈλ‚΄ μ†ŒμŠ€μ½”λ“œ

  • * (Asterisk)λ₯Ό μ‚¬μš©ν•΄ κ°•μ˜μ‹œκ°„ t와 μ„ μˆ˜ κ°•μ˜ node 배열을 μ €μž₯ν•œλ‹€. node 배열을 for문으둜 νƒμƒ‰ν•˜λ©΄μ„œ 인접 리슀트 λ°©ν–₯ κ·Έλž˜ν”„λ₯Ό κ΅¬ν˜„ν•œλ‹€. iλŠ” κ°•μ˜ 번호, node λ°°μ—΄μ˜ μ›μ†ŒλŠ” κ°•μ˜ iλ₯Ό λ“£κΈ° μœ„ν•΄ λ¨Όμ € λ“€μ–΄μ•Ό ν•˜λŠ” μ„ μˆ˜κ°•μ˜μž„μ„ μœ λ…ν•˜μ—¬ κ΅¬ν˜„ν•œλ‹€.
  • μ§„μž…μ°¨μˆ˜κ°€ 0인 λ…Έλ“œλ₯Ό μ°Ύμ•„ queue에 μ €μž₯ν•œλ‹€. μ§„μž…μ°¨μˆ˜κ°€ 0μ΄λΌλŠ” 말은 μ„ μˆ˜ λ…Έλ“œκ°€ μ—†λ‹€λŠ” λœ»μ΄λ―€λ‘œ 이 λ…Έλ“œκ°€ μΆœλ°œλ…Έλ“œμ΄λ‹€.
  • λ°©ν–₯을 거슀λ₯΄μ§€ μ•Šκ³  μΈμ ‘ν•œ λ…Έλ“œλ₯Ό νƒμƒ‰ν•œλ‹€. ν•œ 번 탐색할 λ•Œλ§ˆλ‹€ μ§„μž…μ°¨μˆ˜λ₯Ό 1 κ°μ†Œμ‹œν‚€κ³ , μ§„μž…μ°¨μˆ˜κ°€ 0이 되면 μ„ μˆ˜ λ…Έλ“œκ°€ μ—†λ‹€λŠ” λœ»μ΄λ―€λ‘œ queue에 μ €μž₯ν•œλ‹€.
  • λ¬Έμ œκ°€ "μ΅œμ†Œ μ‹œκ°„"을 κ΅¬ν•˜λŠ” κ²ƒμ΄λ―€λ‘œ min()을 써야 κ² λ‹€κ³  생각할 수 μžˆλ‹€. ν•˜μ§€λ§Œ λ™μ‹œμ— μ—¬λŸ¬ 개의 κ°•μ˜λ₯Ό 듀을 수 있고, μ„ μˆ˜ κ°•μ˜λ₯Ό λͺ¨λ‘ λ“€μ–΄μ•Ό ν•œλ‹€. μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” μ„ μˆ˜ κ°•μ˜λ₯Ό λ¬΄μ‹œν•˜λ©΄ μ•ˆλ˜κ³ , λ°˜λ“œμ‹œ κ³ λ €ν•΄μ€˜μ•Ό ν•œλ‹€. λ”°λΌμ„œ κ°•μ˜ μ‹œκ°„μ΄ 더 였래 κ±Έλ¦¬λŠ” 경우λ₯Ό μ°ΎλŠ”λ‹€λ©΄, max()둜 κ²°κ³Ό ν…Œμ΄λΈ”μ„ κ°±μ‹ ν•΄μ€€λ‹€.
  from collections import deque
  import sys
  si = sys.stdin.readline

  n = int(si())

  time = [0] * (n + 1)
  res = [0] * (n + 1)
  indegree = [0] * (n + 1)  # μ§„μž…μ°¨μˆ˜
  graph = [[] for i in range(n + 1)]


  for i in range(1, n+1):
    t, *node = map(int, si().split())
    time[i] = t
    res[i] = t

    for j in range(len(node)-1):  # λ§ˆμ§€λ§‰ μ›μ†Œ -1
      graph[node[j]].append(i)  # 정점 node[j] --> 정점 i λ°©ν–₯
      indegree[i] += 1  # μ§„μž… 차수λ₯Ό 1 증가


  def topology_sort():
    queue = deque()

    for i in range(1, n + 1):
      if indegree[i] == 0:
        queue.append(i)

    while queue:
      x = queue.popleft()

      for y in graph[x]:
        indegree[y] -= 1
        res[y] = max(res[y], res[x] + time[y])

        if indegree[y] == 0:
          queue.append(y)


  topology_sort()

  for i in range(1, n + 1):
    print(res[i])