[백준] 12850: 본대 산책2 - JAVA
https://www.acmicpc.net/problem/12850
풀이
결론부터 말하면 분할정복을 통해 행렬의 거듭제곱을 하는 문제였다.
각각의 포인트에서 연결된 길을 이차원배열에 저장했다.
초기 배열을 V1이라고 하면 V1[a][b]는 a에서 b로 1분만에 갈 수 있는 경로의 수를 의미한다.
V1을 제곱한 것을 V2라고 하면 V2[a][b]는 a에서 b로 2분만에 갈 수 있는 경우의 수이다.
즉, Vx[a][b]는 a에서 b로 x분만에 갈 수 있는 경우의 수를 의미한다.
따라서 주어진 D만큼 V행렬을 제곱하여 V[0][0]을 구하면 D분만에 0에서 0으로 갈 수 있는 경우의 수이다.
분할정복은 doPow함수로 구현했고, 행렬의 곱셈은 multiply함수로 구현했다.
메모리: 14256KB
시간: 124ms
언어: Java 11
코드
import java.io.*;
import java.util.*;
public class Main {
static long[][] v = {
{ 0, 1, 0, 1, 0, 0, 0, 0 },
{ 1, 0, 1, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 1, 1, 1, 0, 0 },
{ 1, 1, 1, 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0, 1, 1, 0 },
{ 0, 0, 1, 1, 1, 0, 0, 1 },
{ 0, 0, 0, 0, 1, 0, 0, 1 },
{ 0, 0, 0, 0, 0, 1, 1, 0 }
};
final static long MOD = 1_000_000_007;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int D = Integer.parseInt(br.readLine());
long[][] ans = doPow(D);
System.out.println(ans[0][0]);
}
private static long[][] doPow(int n) {
if (n == 1) {
return v;
}
long[][] tmp = doPow(n / 2);
tmp = multyply(tmp, tmp);
if (n % 2 == 1) {
tmp = multyply(tmp, v);
}
return tmp;
}
private static long[][] multyply(long[][] a, long[][] b) {
long[][] tmp = new long[8][8];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
for (int k = 0; k < 8; k++) {
tmp[i][j] = (tmp[i][j] + a[i][k] * b[k][j]) % MOD;
}
}
}
return tmp;
}
}