11. equivalence relation (동치 관계)

Posted by aliontory on April 19, 2024 · 4 mins read

2024-04-19-11. Equivalence Relation (동치 관계)

Equivalence Relation의 정의

  • Relation의 정의
    • 집합 A에 대하여, AxA의 부분집합을 A에 대한 relation이라 한다.
    • ex1) A = {1, 2, 3}일 때, AxA = {(1, 1), (1, 2), (1, 3), (2, 1), ..., (3, 3)}
      • R = {(1, 3), (1, 1), (2, 2)} 는 A의 relation이라 할 수 있다.
      • 이때, (1, 3) ∈R 을 1R3으로 표기한다.
    • ex2) 부등호 <를 N(자연수 집합)의 relation으로써 정의할 수 있다.
      • < = {(1, 2), (1, 3), ..., (2, 3), (2, 4), ...}
      • 2<4는 (2, 4)∈< 를 의미하게 된다.

  • 다음 세 가지를 만족하는 A의 relation R은 equivalence relation이라 한다.
    1. Reflexive : a∈A인 모든 a에 대해, aRa가 성립한다.
    2. Symmetric : a, b∈A인 모든 a, b에 대해, aRb가 성립한다면 bRa도 성립한다.
    3. Transitive : a, b, c∈A 인 모든 a, b, c에 대해, aRb와 bRc가 성립하면 aRc도 성립한다.
  • 직관적으로 말하면, Equivalence Relation은 어떤 특성이 같다는 것을 의미한다.
    • ex) “머리색이 같다” 를 사람들에 대한 동치 관계라 생각하면
    1. Reflexive : 사람 a의 머리색은 당연히 사람 a의 머리색과 같다.
    2. Symmetric : 사람 a와 b의 머리색이 같다면 사람 b와 a의 머리색도 같다.
    3. Transitive : a와 b의 머리색이 같고 b와 c의 머리색이 같으면 a와 c의 머리색도 같다.


Induced Partition

A에 대한 Equivalence Relation R이 주어졌을 때, 

  • R로부터 유도되는 Partition A1, A2, A3, ...이란?
    • Partition은 아래 조건을 만족하는 모든 Ai의 집합을 의미한다.
    • 만약 a∈Ai 이면, aRb일때  b∈Ai 를 만족해야 한다.
    • 단, Ai는 공집합이 아니다.
  • 직관적으로 말하면, 사람의 눈 색이 검은색, 갈색, 파란색 뿐이라고 가정한 경우, 사람들을 눈 색이 검은색, 갈색, 파란색인 세 개의 집합으로 나눈 것이다.

예를 들어, 입력으로 동치 관계가 다음과 같이 주어진다고 하자.

위의 입력으로 주어진 동치 관계에서, (1, 1)등 reflexive 조건에 대한 순서쌍은 생략되었다.
또한 (1, 3)이 주어졌을 때, (3, 1)도 주어져야 하는 것과, (1, 3)과 (3, 9)가 주어졌을 때 (1, 9)가 주어져야 하는 것도 생략되었다.
즉, 유추가 가능한 쌍은 주어지지 않았다.

이때 유도되는 Partition P는
  • P = {A1, A2, A3}
  • A1 = {6, 2}, A2 = {1, 3, 9, 7, 4}, A3 = {5, 10, 8}
이다. 그림(그래프)로 나타내면 다음과 같다.


이러한 Partition은 DFS를 이용하여 찾아낼 수 있다.


DFS를 이용한 Induced Partition 찾기


  1. A의 원소들의 값의 범위가 1~N 일 때, NxN 2차원 배열 M과 길이 N의 1차원 배열 L을 생성한다. 두 배열의 원소들은 0으로 초기화되어 있다. DFS에서 배열 M의 각 행을 방문할 것이다.
  2. 동치 관계의 순서쌍이 입력될 때마다, 2차원에서 해당 순서쌍에 대응하는 위치의 값을 1로 바꾼다. 배열의 값은 다음과 같이 바뀐다.
    • (N=10 인 경우)
  3. 배열 L에서 값이 0인 인덱스를 하나 찾아 변수 i에 대입한다.
    • 변수 i는 현재 방문하고 있는 배열 M의 행 인덱스를 나타낸다.
  4. i를 출력하고, L[i]를 1로 바꾼 뒤 M[i][1]에서 시작하여 값이 1인 칸을 찾을 때까지 M[i][N] 으로 직선 방향으로 이동한다.

  5. 값이 1인 칸을 찾았고, 해당 칸의 열 인덱스가 k라 하자. 

    • L[k]가 0면 L[k]의 값을 1로 고치고 i를 stack에 push한다. 그 다음 i의 값을 k로 고치고 i를 출력한다.

    • L[k]가 1이면 해당 칸을 무시하고, M[i][N] 까지 이동하는 것을 반복한다.
  6. M[i][N] 까지 이동을 마쳤다면, stack에서 pop한다. pop한 값이 k라면, M[k][i]로 이동하고, i를 k로 고치고, 이동을 다시 시작한다.

    • M[3][7]에서 M[7][1]로 이동한 뒤, 7행의 끝까지 이동했다고 하자. 다시 3행으로 돌아오는 경우, M[3][8]부터 보면 된다. 
  7. M[i][N]까지 이동을 마쳤는데도 stack에 남아 있는 값이 없다면, 줄바꿈을 출력한 뒤 3번 과정부터 다시 시작한다. L의 모든 값이 1이라면 알고리즘을 마친다.

알고리즘이 끝났을 때 출력은 다음과 같다.
1 3 7 9 4
2 6
5 10 8
각 행이 Induced Partition의 원소가 된다.


DFS 수행 시간

  1. 배열 L에서 걸리는 시간
    • 각 DFS를 시작할 때, 배열 L의 처음부터 본다면 O(N2) 시간이 걸린다.
    • 배열 L을 어디까지 봤는지를 다른 변수에 기록한다면, 처음부터 시작할 필요가 없다. 이 경우 O(N)이 걸린다.
  2. Stack에서 걸리는 시간
    • stack에서의 push, pop연산은 M에 있는 1개수를 초과하여 수행될 수 없다.
    • 입력값에서 유추가 가능한 쌍은 주어지지 않으므로, 입력값 쌍 개수는 N개 이하여야 하고, 1의 개수는 2N개 이하가 된다.
    • 따라서 stack에서는 O(N) 시간이 걸린다.
  3. M에서 걸리는 시간
    • 각 행을 보는 데 O(N)시간이 걸린다. 행을 반복해서 보지 않고, 행의 개수는 N개이므로, 총 O(N2)시간이 걸린다.


수행 시간을 줄이는 방법

NxN 배열 M을 사용하는 대신, 다음 그림 오른쪽과 같이 각 행의 크기가 다른 배열을 사용한다.
   →     
즉, 기존의 M 배열에서 0인 부분은 생략하는 것이다.
이는 c++의 vector등을 이용하면 된다.

1의 개수는 2N개 이하이므로, 배열에서 걸리는 시간이 O(N2)에서 O(N)으로 줄어들고, 알고리즘의 총 수행 시간은 O(N)이 된다.