Skip to content

삼각형 찾기

pdf로 보기

단순 그래프의 정점의 개수를 n, 간선의 개수를 m이라고 합시다. 이 그래프에 있는 삼각형, 즉 길이 3의 사이클을 모두 찾을 수 있을까요?

O(\frac{nm}{w})

간선 하나 uv를 고정하고, 그 간선을 포함하는 삼각형을 찾아봅시다.

인접 행렬을 만듭니다. 그러면 uv에 인접한 모든 정점 a에 대해 삼각형 uva를 찾을 수 있습니다. 인접 행렬의 u행과 v행에서 둘 다 인접 표시가 된 열을 찾으면 됩니다. 시간 복잡도는 O(nm)입니다.

이 과정을 비트셋의 교집합 연산으로 최적화하면 시간 복잡도 O(\frac{nm}{w})에 모든 삼각형을 찾을 수 있습니다. 64비트 컴퓨터에서 w = 64입니다.

구현

TODO

연습문제

O(m \sqrt m)

정점 v의 차수를 \deg(v)라고 할 때, 다음 식을 생각해 봅시다.

\sum_{uv \in E} \min(\deg(u), \deg(v))

이 값은 O(m \sqrt m)입니다.

증명. \sum_{v \in V} \deg(v) = 2m이므로, \deg(v) \geq \sqrt m인 정점은 많아야 O(\sqrt m)개입니다. 그래프가 단순하므로, \min(\deg(u), \deg(v)) \geq \sqrt m인 간선은 많아야 O(m)개입니다. 나머지 간선은 \min(\deg(u), \deg(v)) \leq \sqrt m입니다. ■

이제 정점을 차수 순으로, 동점일 경우 번호 순으로 정렬해서 위에서 아래로 늘어놓읍시다. 위 v에서 아래 p로 가는 간선을 v \downarrow p라고 합시다.

모든 간선 v \downarrow p에 대해 간선 pq(위아래 상관없음)를 모두 찾을 수 있습니다. 예를 들면 아래와 같은 경우가 있습니다.

Pasted image 20230923182906.png

그러한 (v, p, q) 쌍은 O(\sum_{v \rightarrow p \in E} \deg(p)) = O(m \sqrt m)개 존재합니다. \min(\deg(v), \deg(p)) = \deg(p)이기 때문입니다.

따라서, 위에서 아래로 가는 v \downarrow p \downarrow q 꼴의 경로도 당연히 모두 찾을 수 있습니다.

이제 각 v \downarrow p \downarrow q에 대해 qv가 인접한지 확인하면 됩니다. 간단하게는 해시셋으로 구현할 수 있지만 이는 너무 무겁고, 다음과 같은 방법으로 진행할 수 있습니다. - 우선 크기 n의 배열 A를 초기화합니다. - 각 v에 대해... - 각 간선 v \downarrow p에 대해 A[p]를 마킹합니다. 즉 A[p]는 "pv의 아래에 있으면서 인접하다"라는 뜻입니다. - 다시 각 간선 v \downarrow p에 대해, 간선 p \downarrow q들을 순회합니다. A[q]가 마킹되어 있다면 삼각형 vpq를 찾았습니다. - 다시 각 간선 v \downarrow p에 대해 A[p]의 마킹을 지웁니다.

각 삼각형은 a \downarrow b \downarrow c 꼴의 경로를 정확히 하나씩 갖고 있으므로, 각 삼각형이 정확히 한 번씩 세어집니다. 총 시간 복잡도는 O(m \sqrt m)입니다. 같은 방법으로 그래프에는 삼각형이 최대 O(m \sqrt m)개 있음을 증명할 수 있습니다.

구현

https://jh05013.github.io/ps_snippets/src/ps_snippets/graph/degree_ordered_graph.rs.html

연습문제

추가 연습문제

BOJ 14571 모래시계 in O(m \sqrt m)

모든 삼각형을 O(m \sqrt m)에 찾습니다. 각 정점 v에 대해, v를 포함하는 삼각형 vpq에 대해 간선 pq의 목록을 저장해 둡니다.

모래시계의 중심 v를 고정하고, v에 대한 간선 pq로 이루어진 부분그래프를 생각해 봅시다. 이 부분그래프의 간선 e개 중 두 개를 고르되 겹치는 정점이 없도록 하는 경우의 수를 구하면 됩니다. 첫 번째 간선 ab를 고르고, 나머지 간선 중 a 또는 b와 이어지는 것을 모두 제외하면, 남은 간선의 개수는 e - \deg(a) - \deg(b) + 1입니다. 이때 \deg는 부분그래프 기준입니다.

부분그래프에서 차수를 관리하는 것은 위의 A 배열과 같은 방식으로 진행할 수 있습니다.

사각형의 개수

삼각형뿐만 아니라 사각형도 셀 수 있습니다! 사각형은 최대 O(m^2)개 있을 수 있지만, 개수는 O(m \sqrt m)에 구할 수 있습니다.

메인 아이디어는 아래 그림과 같습니다. 사각형을 v \downarrow p \rightarrow q 꼴의 경로 두 개로 분할할 수 있으니, 그런 형태의 경로를 세는 것입니다. 각 v \downarrow p에 대해, v의 아래에 있으면서 vp에 인접한 정점 q의 개수를 k_{vp}라고 하면, 모든 \frac{k_{vq}(k_{vq}-1)}{2}의 합을 구하면 됩니다.

Pasted image 20230923185408.png

앞에서 보았듯이 k_{vq} > 0(v, q)O(m \sqrt m)개이고, 0보다 큰 모든 k_{vq}O(m \sqrt m)에 구할 수 있습니다.

위 과정을 조금 변형하면 각 정점을 포함하는 사각형의 개수도 셀 수 있습니다.

BOJ 2390 ⎐

제가 이 알고리즘을 배운 계기가 된 문제입니다. 검수하면서 풀이를 고민하다가 "사각형을 O(M^2)보다 빠르게 셀 수 없는데 어떻게 ⎐를 셀 수 있지?"라고 생각했는데, 사각형을 O(M \sqrt M)에 셀 수 있더라고요...

바로 위에서 보았듯이, 각 정점 v에 대해 v를 포함하는 사각형의 개수를 셉니다. 이제 ⎐에서 차수가 4인 정점을 "⎐의 중심"이라고 하면, 각 정점 v에 대해 v가 중심인 ⎐의 개수를 셉니다. 사각형의 개수에 deg(v)-2를 곱하면 됩니다.

모든 v에 대해 위 값을 구하고 합하면, 놀랍게도 크기 5의 완전 그래프에서 출력이 60이 나옵니다. 왜냐하면 다음 🪁 모양 케이스를 제외하지 않았기 때문입니다.

Pasted image 20231002212453.png

🪁를 세기 위해, 각 간선 pq에 대해 pq를 포함하는 삼각형의 개수를 셉니다. 그 후 각 간선 pq에 대해 pq가 사각형의 대각선인 🪁의 개수를 세줍니다. 삼각형의 개수를 k라고 할 때 \binom{k}{2} (deg(p)-3) (deg(q)-3)이 답입니다.

참고로 이 ⎐ 문양의 정체는 NPN open collector로, 전기회로에서 사용하는 문양입니다.

BOJ 28200 4

모든 삼각형을 찾습니다. 각 정점 v에 대해, v를 포함하는 삼각형 vpq에 대해 간선 pq의 목록을 저장해 둡니다.

한 점 v를 고정하고, v에 대한 간선 pq로 이루어진 부분그래프를 생각해 봅시다. 이 부분그래프에서 삼각형의 개수를 세면 되는데, 대부분의 정점에 대해서는 부분그래프가 작을 것이기 때문에 비트셋으로 풀 수 있습니다. 자세한 내용은 에디토리얼을 참조하세요.

참조