mojo's Blog

[백준 11266] 단절점 본문

백준/Graph

[백준 11266] 단절점

_mojo_ 2021. 8. 10. 13:02

문제 링크 => 11266번: 단절점 (acmicpc.net)

 

11266번: 단절점

첫째 줄에 두 정수 V(1≤V≤10,000), E(1≤E≤100,000)가 주어진다. 이는 그래프가 V개의 정점과 E개의 간선으로 이루어져 있다는 의미이다. 다음 E개의 줄에는 간선에 대한 정보를 나타내는 두 정수 A, B

www.acmicpc.net


DFS 트리를 이용하여 단절점을 찾아내는 문제이다.

 

Tarjan's Algorithm 을 이용하여 노드별로 dfs로 방문하면서 매겨지는 dfn값과 해당 노드에서 최소 dfn 값 (low)을 찾는 과정 속에서 단절점을 찾아내는 방법은 다음과 같다.

 

case 1. 자식노드가 dfn 값이 매겨지지 않은 경우 : dfn[cur] <= low[child] 이면서 현재 노드의 부모 노드가 존재하는 경우 현재 노드는 단절점이다.

 

case 2. 부모 노드가 없는 루트 노드의 자식 노드의 갯수가 2개 이상인 경우 해당 루트 노드는 단절점이다.

 

위 2개의 경우를 다음과 같은 예시를 통해 dfn, low 값을 매겨가면서 단절점을 찾아보도록 하자.

 

이러한 connected graph 가 있다고 가정하자.

 

이 그래프를 dfs를 통해 얻어지는 각 노드의 dfn, low 값은 다음과 같이 얻게 된다.

 

(0) 1 : low[1] = dfn[1] = 1 이고 루트 노드 1과 이어진 정점으로 이동

(1) 1 => 2 : low[2] = dfn[2] = 2

(2) 2 => 3 : low[3] = dfn[3] = 3 

(3) 3 => 1 : dfn[3] > dfn[1] 이므로 low[3] = min(low[3], dfn[1]) = 1 으로 update

(4) 3 => 4 : low[4] = dfn[4] = 4

(5) 4 => 2 : dfn[4] > dfn[2] 이므로 low[4] = min(low[4], dfn[2]) = 2 으로 update

(6) 4 => 5 : low[5] = dfn[5] = 5

(7) 5 => 6 : low[6] = dfn[6] = 6 

(8) 6 => 7 : low[7] = dfn[7] = 7

(9) 7 => 5 : dfn[7] > dfn[5] 이므로 low[7] = min(low[7], dfn[5]) = 5 으로 update

(10) 6 => 7 부분에서 low[6] = min(low[6], low[7]) = 5 으로 update

(11) 5 => 6 부분에서 low[5] = min(low[5], low[6]) = 5 으로 update 

(12) 2 => 3 부분에서 low[2] = min(low[2], low[3]) = 1 으로 update

 

생략한 부분이 약간 있지만 대략 이런식으로 dfs가 이뤄지면서 dfn, low 값이 매겨짐을 확인할 수 있다.

 

여기서 case 1 에서의 조건을 통해서 단절점을 찾아본다면 4번 노드와 5번 노드이다.

 

4번 노드인 경우에 4 => 5 로 dfs를 하면서 5번 노드가 최종적으로 얻어진 low 값과 비교한다면 dfn[4] = 4 <= low[5] = 5 를 만족하고 4번 노드는 부모 노드인 3번 노드를 가지고 있으므로 단절점이다.

 

5번 노드인 경우에 5 => 6 로 dfs를 하면서 6번 노드가 최종적으로 얻어진 low 값과 비교한다면 dfn[5] = 5 <= low[6] = 5 를 만족하고 5번 노드는 부모 노드인 4번 노드를 가지고 있으므로 단절점이다.

 

그렇다면 case 2 에서의 조건을 통해 단절점을 찾아본다면 존재하지 않는다.

 

루트 노드인 1번 노드가 1 => 2 => 3 이런식으로 방문을 함으로써 1 => 3 으로 갈 경우 dfn[3] 값이 이미 매겨졌으므로 자식 노드의 갯수가 1개밖에 존재하지 않는다.

 

따라서 다음과 같이 빨간색 원으로 된 부분이 단절점이 된다.

 

 

풀이 code

 

#define _CRT_SECURE_NO_WARNINGS
#include <string>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#define INF 100000000
#define endl '\n'
#define ll long long

using namespace std;

vector<int> v[10001];
int low[10001], dfn[10001], child[10001];
int V, E, nodeNum;
bool ac[10001];

void input() {
	cin >> V >> E;
	for (int i = 0; i < E; i++) {
		int x, y;
		cin >> x >> y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
}

void dfs(int x, int mp = -1) {
	dfn[x] = low[x] = ++nodeNum;

	for (int y : v[x]) {
		if (y == mp) continue; // 부모로 가는 간선 무시
		if (!dfn[y]) { // 방문하지 않은 경우
			child[x]++;
			dfs(y, x);
			low[x] = min(low[x], low[y]);
			if (dfn[x] <= low[y]) {
				if (mp != -1) ac[x] = true; // 부모가 존재하는 경우
			}
		}
		else if (dfn[x] > dfn[y]) { // 조상으로 올라가는 경우
			low[x] = min(low[x], dfn[y]);
		}
	}

	if (mp == -1 && child[x] >= 2) ac[x] = true; // 루트노드의 자식이 2 이상인 경우
}

void solve() {

	for (int i = 1; i <= V; i++) {
		if (!dfn[i]) dfs(i);
	}

	int cnt = 0;
	for (int i = 1; i <= V; i++) {
		if (ac[i]) cnt++;
	}

	cout << cnt << endl;
	for (int i = 1; i <= V; i++) {
		if (ac[i]) cout << i << " ";
	}

}

int main() {

	input();
	solve();

	return 0;
}

 

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

[백준 6672] Electricity  (0) 2021.08.10
[백준 11400] 단절선  (0) 2021.08.10
[백준 2848] 알고스팟어  (0) 2021.07.27
[백준 2637] 장난감 조립  (0) 2021.07.27
[백준 6543] 그래프의 싱크  (0) 2021.07.26
Comments