새소식

알고리즘 테스트 ⏲/백준

[백준] 16947. 서울 지하철 2호선 풀이 (Python, JavaScript)

  • -
 

16947번: 서울 지하철 2호선

첫째 줄에 역의 개수 N(3 ≤ N ≤ 3,000)이 주어진다. 둘째 줄부터 N개의 줄에는 역과 역을 연결하는 구간의 정보가 주어진다. 같은 구간이 여러 번 주어지는 경우는 없고, 역은 1번부터 N번까지 번호

www.acmicpc.net

16947. 서울 지하철 2호선

접근한 방법

그래프에 존재하는 사이클까지 각 노드가 도달가능한 최소 거리를 구하는 문제입니다.

두 가지 과정이 필요합니다.

1. 사이클 그래프 찾기

2. 사이클 그래프로부터 각 노드 도달거리 탐색하기

 

1번에서는 DFS로 사이클이 나올때까지 탐색합니다. 사이클을 찾는 방법은 탐색 출발 노드와 다음 탐색 노드가 같은 경우를 찾으면 됩니다. 단 사이클은 노드가 3개 이상이어야 하므로 깊이가 3회이상인 경우에만 종료할 수 있도록 합니다. 그 외에는 보편적인 DFS 코드와 같고 사이클을 발견하면 나머지 노드들을 탐색하지 않고 바로 종료할 수 있도록 합니다. 그렇지 않으면 이 문제의 컴파일러에서는 시간 초과가 발생합니다.

 

2번에서는 BFS로 사이클 그래프들을 이루고 있는 노드로부터 주변 노드를 탐색합니다. 방문하지 않은 노드들만 탐색하여 깊이를 체크해주면 도달 거리를 기록할 수 있습니다.

 

Python

import sys
sys.setrecursionlimit(10 ** 5)
input = sys.stdin.readline

n = int(input())
graph = [[] for _ in range(n + 1)]
cycle = [3000] * (n + 1) # 사이클까지 각 노드의 도달 거리
for _ in range(n):
    a, b = map(int, input().split())
    graph[a].append(b)
    graph[b].append(a)
visited = [0] * (n + 1)
finded = 0
def find_cycle(d, cnt): # 지나온 노드, 깊이
    global finded
    if finded: # 발견한 경우 시간 단축을 위해 중단
        return
    # 현재 노드와 연결된 노드 탐색
    for i in graph[d[-1]]: 
        if i == d[0] and cnt >= 2: # 사이클인 경우 종료
            for j in d:
                cycle[j] = 0 # j노드는 사이클에 속하는 노드
            finded = 1
            return
        if not visited[i]:
            visited[i] = 1
            find_cycle(d + [i], cnt + 1)
            visited[i] = 0

for i in range(1, n + 1):
    visited[i] = 1
    find_cycle([i], 0)
    visited[i] = 0

# 사이클에 속하는 노드로부터 BFS탐색
from collections import deque
q = deque()
for i in range(1, n + 1): 
    if cycle[i] == 0:
        q.append((i, 0))
while q:
    now, d = q.popleft()
    for v in graph[now]:
        if cycle[v] == 3000: # 방문하지 않은 경우 거리 기록
            cycle[v] = d + 1
            q.append((v, d + 1))
print(*cycle[1:])

JavaScript

function solution(n, list) {
  const graph = Array.from({ length: n + 1 }, () => []);
  const cycle = Array(n + 1).fill(3000);
  const visited = Array(n + 1).fill(0);
  let finded = 0;

  list.forEach((v) => {
    graph[v[0]].push(v[1]);
    graph[v[1]].push(v[0]);
  });

  const findCycle = (passed) => {
    if (finded) return;
    for (const v of graph[passed[passed.length - 1]]) {
      if (v === passed[0] && passed.length >= 3)
        return (finded = 1 && passed.forEach((p) => (cycle[p] = 0)));
      if (!visited[v]) {
        visited[v] = 1;
        findCycle(passed.concat(v));
        visited[v] = 0;
      }
    }
  };

  for (let i = 1; i <= n; i += 1) {
    if (!finded) {
      visited[i] = 1;
      findCycle([i]);
      visited[i] = 0;
    }
  }
  let [q, front] = [[], 0];
  for (let i = 1; i <= n; i += 1) if (!cycle[i]) q.push([i, 1]);
  while (front <= q.length - 1) {
    let [now, d] = q[front++];
    for (const v of graph[now]) {
      if (cycle[v] === 3000) {
        cycle[v] = d;
        q.push([v, d + 1]);
      }
    }
  }
  return cycle.slice(1);
}

solution(12, [[1, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 4], [2, 3], [7, 9], [9, 12], [7, 10], [10, 11],])
Contents

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

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