백준에 순열 사이클 분할(permutation cycle decomposition)이라는 태그가 있어서 공부를 하게 되었다.
기본적인 개념은 다음과 같다.
어떤 순열 (a1,a2,…,an)이 있으면 ai=f(i)인 함수가 있다고 생각해보자.
f2(i)=f(f(i))라고 할 때 i=fk(i)인 1≤k≤n을 찾을 수 있다.
그럼 k번 연산하는 과정에서 나온 수들을 모으면 (f(i),f2(i),…,fk(i))가 나올 것이고 이것을 하나의 순열 사이클이라고 한다.
순열 사이클 안에 존재하는 원소들은 모두 같은 순열 사이클이 될 것이다.
모든 원소에 대해 수행하면 여러개의 순열 사이클이 나오는데 이를 구하는 것을 순열 사이클 분할이라고 한다.
예를 들어보자.
https://www.acmicpc.net/problem/10451
10451번: 순열 사이클
1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열 (3, 2, 7, 8, 1, 4, 5, 6)을 배열을 이용해 표현하면 \(\begin{pmatrix} 1 & 2 &3&4&5&6&7&8 \\ 3
www.acmicpc.net
위 문제의 첫번째 예시는 (3,2,7,8,1,4,5,6)이다.
i=1부터 시작하면 1→3→7→5→1이다.
이를 모든 원소에 대해 수행해보자.
i=2:2→2
i=3:3→7→5→1→3
i=4:4→8→6→4
i=5:5→1→3→7→5
i=6:6→4→8→6
i=7:7→5→1→3→7
i=8:8→6→4→8
중복을 제거하면 순열사이클은 (1,3,7,5),(2),(4,8,6)으로 3개가 나오게 된다.
이런식으로 순열사이클을 직접구하거나 개수를 세는 문제가 주로 나온다.
또한 지난번에 포스팅한 현대대수학에 굉장히 유사한 내용이 있다.
[현대대수학] 8. 치환군
치환 집합 A가 있을 때 일대일 함수 σ:A→A를 A의 치환(Permutation)이라고 한다. 쉽게 말해 정의역 원소의 순서가 있다고 가정할 때 그 순서를 바꾸는 함수를 치환이라고 하는 것이
riroan.tistory.com
[현대대수학] 9. 궤도, 순환치환, 교대군
치환 σ=(1234567838674152)가 있다고 하자. 이 치환을 반복하다보면 유한번(최대 치환 크기)안에 처음 원소 순서로 돌아온다. $\sigma = \begin..
riroan.tistory.com
문제에서 나타내는 순열을 치환으로 보자.
그럼 순열 사이클은 궤도가 된다.
그리고 위 포스트에 "모든 유한집합의 치환들은 여러개의 서로 소인 순환치환들의 곱으로 나타낼 수 있다."라는 성질이 있기 때문에 하나의 순열은 반드시 순열 사이클 분할이 가능하다는게 보장된다.
# O(N)
# arr의 범위를 0~n-1로 가정
def permutation_cycle_decomposition(arr):
n = len(arr)
check = [False] * n
ans = []
for i in range(n):
if not check[i]:
ix = arr[i]
tmp = [i]
check[i] = True
while ix != i:
tmp.append(ix)
check[ix] = True
ix = arr[ix]
ans.append(tmp)
return len(ans), ans
'프로그래밍 > 알고리즘' 카테고리의 다른 글
[알고리즘] Codeforces Round #775 (Div. 2, based on Moscow Open Olympiad in Informatics) (0) | 2022.03.09 |
---|---|
[알고리즘] Codeforces Round #774 (Div. 2) (0) | 2022.03.05 |
[알고리즘] Codeforces Round #772 (Div. 2) (0) | 2022.02.21 |
[알고리즘] Codeforces Round #771 (Div. 2) (0) | 2022.02.15 |
[알고리즘] Codeforces Global Round 19 (0) | 2022.02.14 |