아마 다음은 이미 알고 있을 것이다.
예를들어 거듭제곱되는 수치가 짝수일 때와 홀수일 때를 예로들면 다음과 같다.
A^4 = (A^2)^2 (짝수일때)
A^5 = A * A^4 = A * (A^2)^2 (홀수일때)
만약 A^8이 있다면 원래는 A*A*A*A*A*A*A*A 으로 곱셈 연산을 7번 해야 하지만, A^8을 ((A^2)^2)^2 으로 변경하면 A*A=A', A'^2=A'' 이라 할 시 최종적으로 A'을 구하는데에 A*A로 곱셉 한번, A''=A'*A'을 구하는데도 마찬가지로 곱셈 한번, 최종적으로 A''*A''을 구하는데 곱셈 한 번이 들어간다. 즉 7번의 연산이 3번의 연산으로 줄어든다!
즉, 거듭제곱을 위와 같이 계산한다면 원래 N번의 연산이 O(logN)으로 줄어든다. 여기서 분할정복을 활용한다는 말은 위의 공식을 코드로 짤 때 분할정복을 활용하면 쉽게 짤 수 있기 때문이다. 예를들어 위의 방법을 활용해 자바로 짠 A^N을 구하는 코드는 다음과 같다.
private static long pow(long a, long n) {
if (n == 1)
return a;
long tmp = pow(a, n/2);
if (n%2==0)
return tmp*tmp;
else
return a*tmp*tmp;
}
또한 단순히 정수의 거듭제곱 계산에만 활용한다면 큰 의미는 없겠지만, 이 방법을 활용하면 행렬의 거듭제곱 등 다른 부분에도 응용할 수 있다. 예를들어 피보나치수의 경우 원래 알고 있는 f(n) = f(n-1) + f(n-2) (n>=2, f(0)=0, f(1)=1) 를 계속해서 구하는 것 보다 더 빠르게 다음의 행렬 거듭제곱으로 구할 수 있는 공식이 있다.
여기에도 마찬가지로 행렬의 거듭제곱을 계산하기 위해 위에서 말한 분할정복을 활용해 거듭제곱을 계산할 수 있다. 자바 코드로 구현해보면 다음과 같다. (MOD의 경우는 값이 너무 커지므로 해당 값으로 나눈 나머지를 출력한 것이다.)
private static final long MOD = 1000007l;
private long[][] matrixMult(long[][] a, long[][] b) {
long[][] arr = new long[2][2];
arr[0][0] = (a[0][0]*b[0][0]%MOD + a[0][1]*b[1][0]%MOD)%MOD;
arr[1][0] = (a[0][0]*b[0][1]%MOD + a[0][1]*b[1][1]%MOD)%MOD;
arr[0][1] = (a[1][0]*b[0][0]%MOD + a[1][1]*b[1][0]%MOD)%MOD;
arr[1][1] = (a[1][0]*b[0][1]%MOD + a[1][1]*b[1][1]%MOD)%MOD;
return arr;
}
private long[][] fibo(long n) {
if (n == 1) {
long[][] arr = {{1,1},{1,0}};
return arr;
}
long[][] tmp = fibo(n/2);
if (n%2==1) {
return matrixMult(matrixMult(tmp, tmp), fibo(1));
} else {
return matrixMult(tmp, tmp);
}
}
위의 로직을 사용할 시, 1,000,000,000,000,000,000 번째 피보나치조차도 O(logN)을 하면 사실 60번의 행렬 곱셈만으로 구할 수 있다(2^60 = 1,152,921,504,606,846,976). 진짜 저걸 다 곱해보면 대략 317년정도 걸릴 연산(대략 1억번 연산에 1초정도로 잡았다.)이 로직 좀 변경했다고 0.1초도 안되서 끝나는 것이다.
'CS > Algorithms' 카테고리의 다른 글
벡터의 외적과 CCW (Counter ClockWise) (4) | 2022.11.15 |
---|---|
누적 합(prefix sum), 2차원 누적합(prefix sum of matrix) with java (10) | 2022.08.09 |
에라토스테네스의 체 혹은 소수판정 시 제곱근 까지만 확인하면 되는 이유 (4) | 2022.02.12 |
백트래킹 알고리즘 (Back Tracking) (0) | 2021.10.03 |
BFS 알고리즘 (너비 우선 탐색) - 배열 BFS, 그래프 BFS (2022-08-27 업데이트) (10) | 2021.09.24 |
댓글