1533번: 길의 개수
첫째 줄에 교차점의 개수 N이 주어진다. N은 10보다 작거나 같고, 시작점의 위치 S와 끝점의 위치 E, 그리고 정문이가 늦는 시간 T도 주어진다. S와 E는 N보다 작거나 같은 자연수이다. T는 1,000,000,000
www.acmicpc.net
이 문제는 S에서 출발하여 T분 뒤에 E에 도착하는 경우의 수를 구하는 문제이다.
여기서 이 그래프의 각 간선에 가중치가 0~5까지 설정되어있으므로 그 경우를 나눠서 계산하자.
다음은 이 문제를 풀기 위한 행렬 mat을 block matrix로 표현한 것이다. 각 block은 N by N 행렬이다.
a_i -> a_(i+1) 경로수 |
a_(i-1) -> a_(i+1) 경로수 |
a_(i-2) -> a_(i+1) 경로수 |
a_(i-3) -> a_(i+1) 경로수 |
a_(i-4) -> a_(i+1) 경로수 |
a_i를 옮김 | 0 | 0 | 0 | 0 |
0 | a_(i-1)을 옮김 | 0 | 0 | 0 |
0 | 0 | a_(i-2)를 옮김 | 0 | 0 |
0 | 0 | 0 | a_(i-3)를 옮김 | 0 |
이 행렬을 곱할 벡터 vec의 초기값은 다음과 같다. 각 block의 성분은 N개이다.
a_0: 시작점만 1, 나머지 점은 0 |
0 |
0 |
0 |
0 |
이렇게 설정하면 mat의 T제곱을 vec에 곱해 나온 첫 블럭은 점 S에서 출발해 점 1~N까지 도달하는 경우의 수를 담게 된다. mat의 T제곱은 binary exponentiation을 통해 빠르게 계산할 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::string;
long long mat[60][50];
long long tempmat[50][50];
long long vec[50];
long long tempvec[50];
int main()
{
int N, S, E, T;
cin >> N >> S >> E >> T;
vec[S - 1] = 1; // 시작점 초기값 1, 나머지 0
string x;
for (int i = 0;i < N;i++) {
cin >> x;
for (int j = 0;j < N;j++) { // adjacency matrix의 transpose에서 1인 성분들
if (x[j] == '1') {
mat[j][i] = 1;
}
}
for (int j = 0;j < N;j++) { // adjacency matrix의 transpose에서 2인 성분들
if (x[j] == '2') {
mat[j][i + N] = 1;
}
}
for (int j = 0;j < N;j++) { // adjacency matrix의 transpose에서 3인 성분들
if (x[j] == '3') {
mat[j][i + 2 * N] = 1;
}
}
for (int j = 0;j < N;j++) { // adjacency matrix의 transpose에서 4인 성분들
if (x[j] == '4') {
mat[j][i + 3 * N] = 1;
}
}
for (int j = 0;j < N;j++) { // adjacency matrix의 transpose에서 5인 성분들
if (x[j] == '5') {
mat[j][i + 4 * N] = 1;
}
}
}
for (int i = 0;i < 5 * N;i++) { // 지나간 네 개의 경우를 아래로 옮김
mat[i + N][i] = 1;
}
while (T > 0) { // binary exponentiation
if (T & 1) {
for (int i = 0; i < 5 * N; i++) {
for (int k = 0; k < 5 * N; k++) {
tempvec[i] += mat[i][k] * vec[k];
}
}
for (int i = 0; i < 5 * N; i++) {
vec[i] = tempvec[i] % 1000003;
tempvec[i] = 0;
}
}
for (int i = 0; i < 5 * N; i++) {
for (int j = 0; j < 5 * N; j++) {
for (int k = 0;k < 5 * N;k++) {
tempmat[i][j] += mat[i][k] * mat[k][j];
}
}
}
for (int i = 0; i < 5 * N; i++) {
for (int j = 0; j < 5 * N; j++) {
mat[i][j] = tempmat[i][j] % 1000003;
tempmat[i][j] = 0;
}
}
T >>= 1;
}
cout << vec[E - 1]; // E번 노드까지 가는 경로의 수
return 0;
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 6603 // C++] 로또 (0) | 2021.01.23 |
---|---|
[BOJ 15610 // C++] Abbey Courtyard (0) | 2021.01.22 |
[BOJ 13328 // C++] Message Passing (0) | 2021.01.20 |
[BOJ 12850 // C++] 본대 산책 2 (0) | 2021.01.19 |
[BOJ 13171 // C++] A (0) | 2021.01.18 |