백준 10830번 : 행렬 제곱 with Java
Algorithm/백준import java.io.*;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static StringTokenizer st = null;
public static void main(String[] args) throws IOException {
int n;
long b;
long[][] matrix;
long[][] result;
Stack<Integer> stack = new Stack<>();
st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
b = Long.parseLong(st.nextToken());
matrix = new long[n][n];
result = new long[n][n];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++) {
matrix[i][j] = Long.parseLong(st.nextToken());
result[i][j] = matrix[i][j];
}
}
while (b > 0)
{
if (b % 2 == 1)
stack.add(1);
else
stack.add(0);
b /= 2;
}
stack.pop();
while (!stack.isEmpty()) {
long bit = stack.pop();
result = mul(result, result, n);
if (bit != 0) {
result = mul(result, matrix, n);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(result[i][j] % 1000 + " ");
}
System.out.println();
}
}
private static long[][] mul(long[][] matrix1, long[][] matrix2, int n) {
long[][] n_matrix;
n_matrix = new long[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
long result = 0;
for (int k = 0; k < n; k++) {
result += matrix1[i][k] * matrix2[k][j];
result %= 1000;
}
n_matrix[i][j] = result;
}
}
return (n_matrix);
}
}
문제에서 확인할 수 있듯이, 최대 행렬의 1000억 제곱까지 구해야 한다.
따라서 단순 Brute Force로 풀게 되면 시간이 팡팡 터지는 문제다.
그럼 어떻게 시간을 줄일 수 있을까?
개념은 정수의 N 거듭제곱 빠르게 구하기와 동일하다.
위 표는 11승을 구하는 방법이다.
11을 2진수로 표현하면 1011 이고, 이를 행렬 곱에 적용한다면 1일때 제곱을 한 뒤에 입력받은 행렬을 곱해준다.
0일때는 제곱만 한다.
조건은 매우 간단하다.
입력받은 B를 나눠서 2진수를 Stack에 담아주게 되면 최상위 비트부터 뽑아서 확인할 수 있다.
while (b > 0)
{
if (b % 2 == 1)
stack.add(1);
else
stack.add(0);
b /= 2;
}
다음 스택에서 무조건 한 개 꺼내준다.
그 이유는 다음과 같다. => 문제에서 주어지는 값이 최상위 비트가 항상 1임을 보장한다.
따라서 최상위 비트 계산을 할 필요없이, 주어지는 입력 행렬로 시작하면 된다.
'Algorithm > 백준' 카테고리의 다른 글
백준 6087번 : 레이저 통신 [Java] (0) | 2020.12.09 |
---|---|
백준 6549번 : 히스토그램에서 가장 큰 직사각형 [Java] (0) | 2020.12.09 |
백준 9376번 : 탈옥 [Java] (0) | 2020.12.07 |
백준1655번 : 가운데를 말해요 [java] (0) | 2020.11.30 |
백준12865번 : 평범한 배낭 (0) | 2020.11.26 |