문제 링크
노드 사이에 사이클이 발생하면 "연합"이 된다. 각 사이클의 노드가 인접하면 인접한 사이클끼리도 연합이 된다. 이 연합 집합의 개수를 출력하는 문제이다.
이 문제는 그래프에서 사이클을 찾고 집합의 구성을 분류하는 기초적인 문제라 개념 잡기에 좋은 문제인듯 하다.
접근법
사이클을 찾고 해당 사이클이 집합을 이루는지 찾아야 한다. 이 문제는 BFS 또는 Union-Find로 풀릴 수 있다.
먼저 각 노드가 사이클을 가지고 있는지는 어떻게 확인할까? 무지성 includes
를 해도 되지만 O(1)
로 찾지 않으면 시간초과가 발생한다.
문제가 친절하게도 각 정점 사이의 직접 사이클만 요구하므로 사이클을 더 쉽게 찾을 수 있다.
각 노드의 사이클 여부를 확인할 수 있게 되었으니 집합을 구성해 주어야 한다.
BFS로 집합 구성하기
인접한 노드끼리 사이클이면서 사이클끼리 인접하면 연합이 된다.
따라서 우리는 각 노드를 순회하면서 사이클을 찾고 사이클이 되는 노드에서 다시 사이클을 찾는 식으로 BFS 탐색을 하면 된다.
따라서 각 노드에서 사이클이 되는 노드를 찾고 해당 노드를 큐에 넣어줌으로써 연속된 사이클을 계속해서 찾을 수 있다.
Union-Find로 집합 구성하기
그래프의 집합을 나타내는 방법으로 Union-Find를 사용할 수 있다.
노드를 순회하면서 Union 조건이 성립(사이클)한다면 각 노드를 합쳐준다.
이후 각 노드의 부모 노드를 find 한다. 노드의 부모가 같다면 같은 집합이라는 뜻이 된다.
Union-Find에서는 memo 배열을 통한 방문 여부 확인 코드가 없는 것을 알 수 있다.
- BFS의 경우 인접한 모든 노드를 방문하면서 방문 여부로 집합을 구성하지만, Union-Find는 각 노드의 부모로 집합 여부를 확인하기 때문에 사이클이 된다면 각 노드의 부모를 계속해서 갱신해 줘야 한다.
이때 부모 배열의 값으로만 비교해 출력하면 오답이 된다.
모든 노드를 순회하면서 부모를 갱신하지 않았기 때문에 마지막에 각 노드를 다시 find 해서 부모를 갱신해야 올바른 값이 된다.
정리
- 양방향 그래프를 그린다.
- 노드를 순회하면서 사이클 여부를 확인한다.
- 사이클인 노드들을 집합으로 구분한다.
- 집합의 개수를 출력한다.
최종 코드