백준 No.11266 [단절점]
본문 바로가기
Algorithm (C++ based)/BOJ

백준 No.11266 [단절점]

by 조훈이 2021. 8. 21.

BOJ No.11266 [단절점]


  문제 

11266번: 단절점 (acmicpc.net)

 

11266번: 단절점

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

www.acmicpc.net


  설명 

 <알고리즘 분류> 
 * 그래프
 * 단절점

 

 단절점 
: 어떠한 그래프에서 임의의 정점을 제거했을 때 두 개 이상의 그래프들로 나누어지게 하는 정점

  개념 자체는 간단하다. 위 그래프에서 단절점은 3, 5 번째 정점이 될 것이다. 3번 정점을 제거함으로써 3개의 그래프로 나뉘어지고, 5번 정점을 제거함으로써 2개의 그래프로 나뉘어졌기 때문이다.

 

  단절점에 대한 파악은 루트노드부터 깊이 우선 탐색으로 정점들을 방문하면서, 그 때 가지는 방문 순서를 기준으로 파악한다.

 

 

  1번째 정점을 루트노드라고 할 때 방문 깊이 우선 탐색(DFS) 를 통한 노드들의 방문순서는 위와 같이 정의할 수 있다. 보면 단절점인 3, 5 번째 정점을 보면 공통적인 특성이 있다. 단절점들은 바로 다음 방문되는 정점부터 DFS를 진행했을 때 해당 단절점의 방문 순서보다 이르게 방문이 된 정점을 만나지 않는다. 단절점으로 하여금 이전에 방문이 되었던 정점들과 이후에 방문이 될 정점들이 각각의 그래프를 형성하게 되는 것 이다.

  그렇다면 단절점이 아닌 2번 정점은? 다음으로 방문되는 정점들 중 4번 정점이 2번 정점보다 이전에 방문한 1번 정점을 만나는 것을 확인할 수 있다. 고로 2번 정점은 단절점이 아니다.

 

  여기서 주의깊게 여겨야 할 요소가 있다. 바로 루트노드 이다. 루트노드는 모든 정점들 중 가장 먼저 방문이 된 정점이므로 위와 같은 특성을 이용해 단절점 여부를 파악할 수 없다.위 공식을 루트노드에 적용하면 루트노드는 항상 단절점이 되기 때문이다. 루트노드는 자식 그룹의 개수가 2개 이상이면 단절점으로 여긴다. 아래 루트노드 (1번 정점) 은 자식 그룹을 3개 가지고 있으므로 단절점에 해당한다.

  문제에서 두 정점이 연결이 된 양방향 간선들에 대한 정보를 준다. 그 정보들을 통해 위와 같이 그래프를 만든 후 위와 같은 특성과 DFS 알고리즘을 통해 단절점들을 파악할 수 있다.

 

 <정리> 
1. 루트노드가 자식 정점들의 그룹을 2개 이상 가지고 있다면 루트노드는 단절점이다.
2. 루트 노드가 아닌 모든 노드들은 방문 순서를 통해 단절점 여부를 파악한다.
   2-1. 단절점 여부를 파악하려는 정점 바로 다음 정점부터 탐색되는 정점들이 파악하려는 정점보다 이전에 방문된 정점과 만난 적이 있다면 이 점은 단절점이 아니다.
   2-2. 단절점 여부를 파악하려는 정점 바로 다음 정점부터 탐색되는 정점들 모두 파악하려는 정점 보다 같거나 큰 방문 순서를 가지고 있다면? 이 점은 단절점이다.

  Code 

더보기
#include <iostream>
#include <vector>
#include <queue>
#define MAX 100000

using namespace std;

priority_queue<int, vector<int>, greater<int>> ans;
vector<vector<int>> adj;
vector<int> visitCount;
vector<bool> ansCount;
int v, e;
int cnt = 1;

int dfs(int curVer, bool isRoot, int parent) {
	visitCount[curVer] = cnt++;

	int minVisit = visitCount[curVer];
	int childCount = 0;
	int low = MAX;

	for (auto curChild : adj[curVer]) {
		if (curChild == parent) continue;
										
		if (visitCount[curChild] == 0) {
			childCount++;	

			low = dfs(curChild, false, curVer);

			if (!isRoot && low >= visitCount[curVer]) {
				if (!ansCount[curVer]) {		
					ans.push(curVer);
					ansCount[curVer] = true;
				}
			}

			minVisit = min(minVisit, low);
		}
		else minVisit = min(minVisit, visitCount[curChild]);
	}

	if (isRoot && 2 <= childCount) {
		if (!ansCount[curVer]) {
			ans.push(curVer);
			ansCount[curVer] = true;
		}
	}

	return minVisit;
}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	cin >> v >> e;
	adj.resize(v + 1);
	ansCount.assign(v + 1, false);
	visitCount.assign(v + 1, 0);

	for (int i = 1; i <= e; i++) {
		int a, b; cin >> a >> b;

		adj[a].push_back(b);
		adj[b].push_back(a);
	}

	for (int i = 1; i <= v; i++) {
		if (visitCount[i] == 0)
			dfs(i, true, 0);
	}

	cout << ans.size() << '\n';

	while (!ans.empty()) {
		cout << ans.top() << ' ';
		ans.pop();
	}
}
728x90

'Algorithm (C++ based) > BOJ' 카테고리의 다른 글

백준 No.11400 [단절선]  (0) 2021.08.29
백준 No.3190 [뱀]  (0) 2021.08.26
백준 No.1261 [알고스팟]  (0) 2021.08.17
백준 No.1626 [두 번째로 작은 스패닝 트리]  (0) 2021.08.17
백준 NO.13537 [수열과 쿼리 1]  (0) 2021.08.14

댓글