새소식

PS/백준

[백준/9470] Strahler 순서 (Python)

  • -

Problem : https://www.acmicpc.net/problem/9470

 

9470번: Strahler 순서

지질학에서 하천계는 유향그래프로 나타낼 수 있다. 강은 간선으로 나타내며, 물이 흐르는 방향이 간선의 방향이 된다. 노드는 호수나 샘처럼 강이 시작하는 곳, 강이 합쳐지거나 나누어지는 곳

www.acmicpc.net

 

Difficulty : Gold 3

 

Status : Solved

 

Time : 00:19:18

 


 

문제 설명

 

더보기

 

지질학에서 하천계는 유향그래프로 나타낼 수 있다. 강은 간선으로 나타내며, 물이 흐르는 방향이 간선의 방향이 된다. 노드는 호수나 샘처럼 강이 시작하는 곳, 강이 합쳐지거나 나누어지는 곳, 바다와 만나는 곳이다.

 

 

네모 안의 숫자는 순서를 나타내고, 동그라미 안의 숫자는 노드 번호를 나타낸다.

하천계의 Strahler 순서는 다음과 같이 구할 수 있다.

 

  • 강의 근원인 노드의 순서는 1이다.
  • 나머지 노드는 그 노드로 들어오는 강의 순서 중 가장 큰 값을 i라고 했을 때, 들어오는 모든 강 중에서 Strahler 순서가 i인 강이 1개이면 순서는 i, 2개 이상이면 순서는 i+1이다.

하천계의 순서는 바다와 만나는 노드의 순서와 같다. 바다와 만나는 노드는 항상 1개이며, 위의 그림의 Strahler 순서는 3이다.

하천계의 정보가 주어졌을 때, Strahler 순서를 구하는 프로그램을 작성하시오.

실제 강 중에서 Strahler 순서가 가장 큰 강은 아마존 강(12)이며, 미국에서 가장 큰 값을 갖는 강은 미시시피 강(10)이다.

노드 M은 항상 바다와 만나는 노드이다.

 

 

입력 및 출력

 

더보기

입력

 

첫째 줄에 테스트 케이스의 수 T (1 ≤ T ≤ 1000)가 주어진다.

각 테스트 케이스의 첫째 줄에는 K, M, P가 주어진다. K는 테스트 케이스 번호, M은 노드의 수, P는 간선의 수이다. (2 ≤ M ≤ 1000) 다음 P개 줄에는 간선의 정보를 나타내는 A, B가 주어지며, A에서 B로 물이 흐른다는 뜻이다. (1 ≤ A, B ≤ M) M은 항상 바다와 만나는 노드이며, 밖으로 향하는 간선은 존재하지 않는다.

 

출력

 

각 테스트 케이스마다 테스트 케이스 번호와 입력으로 주어진 하천계의 Strahler 순서를 한 줄에 하나씩 출력한다.

 

입력 예시

 

1
1 7 8
1 3
2 3
6 4
3 4
3 5
6 7
5 7
4 7

 

출력 예시

 

1 3

 

 


 

풀이

 

위상 정렬 문제. 간단히 복습을 위해 위상 정렬 방식을 정리하면...

 

  • 엣지 방향을 통해 각 노드의 진입 차수를 구하고
  • 진입 차수가 0인 노드들을 초기화 후 큐에 삽입하여
  • BFS를 수행하되, 현재 시점의 노드와 연결된 다음 노드의 진입 차수를 1씩 줄이고
  • 만약 진입 차수가 0이 된 노드가 존재한다면 큐에 삽입한다.

 

이렇게 하면 위상에 따라 순차적으로 접근할 수 있다.

이 문제는 여기에 Strahler 순서 개념을 도입했다. Strahler 순서가 2 이상인 노드의 경우, 진입 차수가 0이 될 때까지 큐에 삽입되지 않음이 보장된다. 즉 이 노드들에 대해 직전의 Strahler 순서를 모두 업데이트할 수 있으므로, 다음 노드 접근시마다 strahler 순서의 최댓값을 업데이트하는 방식을 채용하도록 한다.

 

그렇다면 현재 노드에 접근할 때 Strahler 순서가 최댓값임이 보장되며, 최댓값의 경우의 수가 2 이상이라면 최댓값에 +1을 갱신 후 탐색을 이어나갈 수 있다. 모든 탐색이 종료된 후, 바다라고 확정된 M번째 노드의 Strahler 순서를 출력하면 된다.

 

 

 

풀이 코드

from collections import defaultdict, deque
import sys
input = sys.stdin.readline

def solve() :
  K, M, P = map(int, input().split())
  edge_dict = defaultdict(list)
  indegree_list = [0]*M
  visited = [False]*M
  strahler_list = [[0]*2 for _ in range(M)]
  q = deque()
  
  for _ in range(P) :
    a, b = map(int, input().split())
    edge_dict[a-1].append(b-1)
    indegree_list[b-1] += 1

  for i in range(M) :
    if indegree_list[i] == 0 :
      q.append(i)
      visited[i] = True
      strahler_list[i] = [1, 1]

  while q :
    node = q.popleft()
    if strahler_list[node][1] > 1 :
      strahler_list[node][0] += 1
    
    for nxt in edge_dict[node] :
      indegree_list[nxt] -= 1
      if strahler_list[nxt][0] < strahler_list[node][0] :
        strahler_list[nxt] = [strahler_list[node][0], 1]
      elif strahler_list[nxt][0] == strahler_list[node][0] :
        strahler_list[nxt][1] += 1
      if not indegree_list[nxt] :
        q.append(nxt)
  print(K, strahler_list[-1][0])

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

풀이 완료!

'PS > 백준' 카테고리의 다른 글

[백준/1607] 원숭이 타워 (Python)  (2) 2023.09.18
[백준/1771] 카드 묶음 (Python)  (1) 2023.09.18
[백준/12966] 턴 게임 (Python)  (0) 2023.09.17
[백준/11266] 단절점 (Python)  (0) 2023.09.13
[백준/1219] 오민식의 고민 (Python)  (0) 2023.09.12
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.