첫 번째 줄에 N, K (1 ≤ N ≤ 100, 1 ≤ K ≤ 109) 이 공백을 구분으로 주어진다.
다음 N개의 줄에 걸쳐 민호가 작성한 인접 행렬이 주어진다. i번 줄의 j번 수가 1이면 i번 마을과 j번 마을의 길이 있다는 얘기고 0이면 길이 존재하지 않는다는 이야기 이다.
출력
길이가 K인 경로의 수를 10^9+7로 나눈 나머지를 출력한다.
입력 예시
4 2
0 1 1 0
0 0 1 0
0 0 0 1
1 0 0 0
출력 예시
6
풀이
인접행렬의 특성을 생각해보자. 행렬의 K제곱을 수행했을 때, 그 행렬의 원소 mat[i][j]는 i에서 j로 k번의 경로를 거쳐 가는 경우의 수와 동일하다. 즉 행렬의 거듭제곱을 빠르게 구하는 것이 핵심이다. O(N^3logK) 시간복잡도로 분할 정복을 이용한 풀이가 가능하다.
풀이 코드
import sys
input = sys.stdin.readline
MOD = 10**9+7
N, K = map(int, input().split())
adj_mat = [list(map(int, input().split())) for _ in range(N)]
def matmul(A, B) :
res = [[0]*N for _ in range(N)]
for i in range(N) :
for j in range(N) :
for k in range(N) :
res[i][j] = (res[i][j] + A[i][k]*B[k][j]) % MOD
return res
def matpow(m, k) :
if k == 1 :
return m
p = matpow(m, k//2)
p = matmul(p, p)
if k % 2 :
p = matmul(p, m)
return p
res = matpow(adj_mat, K)
print(sum(map(sum, res)) % MOD)