문제
- 문제 링크
BOJ 16947 - 서울 지하철 2호선
$N$개의 정점과 간선으로 이루어진 그래프가 주어진다.
임의의 두 역 사이에 경로가 항상 존재할 때, 각 노드로부터 사이클 형상 까지의 거리를 구해보자.
TL : $2$ sec, ML : $512$ MB
$3 ≤ N ≤ 3,000$
알고리즘 분류
- 그래프 이론(graphs)
- 그래프 탐색(graph_traversal)
- 깊이 우선 탐색(dfs)
- 너비 우선 탐색(bfs)
풀이
$N$개의 간선으로 이루어진 그래프에서 사이클을 떼네어볼 수 있는가를 묻는 교육적인 문제이다.
나는 개인적으로 indegree를 이용한 bfs를 이용해 사이클을 분리하는 방식을 선호한다.
다음의 과정을 보자.
- 간선 정보를 입력 받으면서 indegree를 카운트 해주면, 리프 노드는 indegree가 $1$인 노드들이다.
- 리프 노드들로부터 bfs를 시작하자. 이때 마주치는 인접 노드들마다 indegree를 감소 시켜 주고 $1$이 됐다면 큐에 넣자.
- 위 과정에서 방문하게 되는 노드들마다 표시를 해두고 나면, 최종적으로 사이클에 속한 노드들을 제외한 모든 노드들에 표시가 완료된다.
이제 우리는 그래프를 다음과 같이 새로운 시선으로 바라 볼 수 있다.
"사이클에 속한 정점들을 루트로 하는 $k$개의 트리"
각 $k_i$의 정점으로부터 하위 노드로의 탐색으로 문제의 정답을 모두 채워줄 수 있다.
전체 코드
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 | #include<bits/stdc++.h> #define N 3001 using namespace std; vector <int> Gr[N]; int n, C[N], Cy[N], W[N]; void f() { queue <int> Q; for (int i(1); i <= n; i++) if (C[i] == 1) Cy[i] = 1, Q.push(i); while (Q.size()) { int x(Q.front()); Q.pop(); for (int i : Gr[x]) if (--C[i] == 1 && !Cy[i]) Cy[i] = 1, Q.push(i); } } void f(int p, int q, int w) { for (int i : Gr[p]) if (i ^ q && Cy[i]) W[i] = w, f(i, p, w + 1); } int main() { cin >> n; for (int o{}, i, j; o++ < n; C[i]++, C[j]++) scanf("%d %d", &i, &j), Gr[i].push_back(j), Gr[j].push_back(i); f(); for (int i(1); i <= n; i++) if (!Cy[i]) f(i, i, 1); for (int i(1); i <= n; printf("%d ", W[i++])); } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Gold)' 카테고리의 다른 글
백준 2550 - 전구 (C++) (1) | 2023.04.23 |
---|---|
백준 20440 - 🎵니가 싫어 싫어 너무 싫어 싫어 오지 마 내게 찝쩍대지마🎵 - 1 (C++) (0) | 2023.04.23 |
백준 16920 - 확장 게임 (C++) (0) | 2023.04.23 |
백준 27924 - 윤이는 엄청난 것을 훔쳐갔습니다 (C++) (0) | 2023.04.23 |
백준 27978 - 보물 찾기 2 (C++) (1) | 2023.04.23 |