백준 10830번 (행렬 제곱, C++) [BAEKJOON]

행렬 제곱

https://www.acmicpc.net/problem/10830

시간 제한메모리 제한제출정답맞힌 사람정답 비율
1 초256 MB2975910520833934.120%

문제

크기가 N*N인 행렬 A가 주어진다.

이때, A의 B제곱을 구하는 프로그램을 작성하시오.

수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.

입력

첫째 줄에 행렬의 크기 N과 B가 주어진다.

(2 ≤ N ≤  5, 1 ≤ B ≤ 100,000,000,000)

둘째 줄부터 N개의 줄에 행렬의 각 원소가 주어진다.

행렬의 각 원소는 1,000보다 작거나 같은 자연수 또는 0이다.

출력

첫째 줄부터 N개의 줄에 걸쳐 행렬 A를 B제곱한 결과를 출력한다.

예제 입력 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
2 5
1 2
3 4
2 5 1 2 3 4
2 5
1 2
3 4

예제 출력 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
69 558
337 406
69 558 337 406
69 558
337 406

예제 입력 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
3 3
1 2 3
4 5 6
7 8 9
3 3 1 2 3 4 5 6 7 8 9
3 3
1 2 3
4 5 6
7 8 9

예제 출력 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
468 576 684
62 305 548
656 34 412
468 576 684 62 305 548 656 34 412
468 576 684
62 305 548
656 34 412

예제 입력 3

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
5 10
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
5 10 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1
5 10
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1

예제 출력 3

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512 512 0 0 0 512 512 0 0 0 512 512 0 0 0 512 512 0 0 0 512
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512
512 0 0 0 512

추가 반례

https://www.acmicpc.net/board/search/all/problem/10830

예제 입력 A

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
2 1
1000 1000
1000 1000
2 1 1000 1000 1000 1000
2 1
1000 1000
1000 1000

예제 출력 A

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
0 0
0 0
0 0 0 0
0 0
0 0

예제 입력 B

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
2 100000000000
999 998
997 996
2 100000000000 999 998 997 996
2 100000000000
999 998
997 996

예제 출력 B

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
751 250
875 626
751 250 875 626
751 250
875 626

출처

  • 문제를 만든 사람: baekjoon
  • 데이터를 추가한 사람: doju
  • 잘못된 조건을 찾은 사람: dreammusic23

알고리즘 분류


통과된 코드

입력 받는 B 값이 int의 범위를 벗어나는 경우를 조심

행렬을 B만큼 곱하는 연산을 할 필요가 없이 효율적으로 처리

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 새로운 데이터 유형을 정의
typedef vector<vector<unsigned long long int>> Matrix;
long long int _N, _B;
constexpr int MOD = 1000;
// 행렬 제곱 계산
Matrix MatrixMultiply(Matrix& A, Matrix& B) {
int _Size = A.size();
Matrix _Temp(_Size, vector<unsigned long long int>(_Size));
for (int i = 0; i < _Size; i++) {
for (int j = 0; j < _Size; j++) {
unsigned long long int _Sum = 0;
for (int k = 0; k < _Size; k++) // 모듈러 연산
_Sum += ((A[i][k] % MOD) * (B[k][j] % MOD)) % MOD;
_Temp[i][j] = _Sum % MOD;
}
}
return _Temp;
}
// 행렬을 제곱합니다.
Matrix MatrixPow(Matrix& p_Matrix, unsigned long long int p_Cnt) {
long long int _Size = p_Matrix.size();
Matrix _Res(_Size, vector<unsigned long long int>(_Size));
// 항등 행렬로 초기화 => _Res는 거듭제곱의 곱을 누적하는 데 사용
for (int i = 0; i < _Size; i++)
_Res[i][i] = 1;
while (p_Cnt > 0) {
// 지수가 홀수인 경우 현재 _Res행렬과 입력 행렬을 곱하고 다시 할당
if (p_Cnt % 2 == 1) _Res = MatrixMultiply(_Res, p_Matrix);
p_Matrix = MatrixMultiply(p_Matrix, p_Matrix);
p_Cnt /= 2;
// p_Matrix => A
// cnt = 4 > A * A * A * A
// cnt = 2 > (A * A) * (A * A)
// cnt = 1 > ((A * A) * (A * A))
}
return _Res;
}
int main()
{
cin >> _N >> _B;
// 동적으로 행렬 생성
Matrix _Matrix(_N, vector<unsigned long long int>(_N));
for (int i = 0; i < _N; i++) {
for (int j = 0; j < _N; j++)
cin >> _Matrix[i][j];
}
// 제곱 시작
Matrix C = MatrixPow(_Matrix, _B);
for (int i = 0; i < _N; i++) {
for (int j = 0; j < _N; j++)
cout << C[i][j] << " ";
cout << "\n";
}
return 0;
}
#include <iostream> #include <vector> #include <algorithm> using namespace std; // 새로운 데이터 유형을 정의 typedef vector<vector<unsigned long long int>> Matrix; long long int _N, _B; constexpr int MOD = 1000; // 행렬 제곱 계산 Matrix MatrixMultiply(Matrix& A, Matrix& B) { int _Size = A.size(); Matrix _Temp(_Size, vector<unsigned long long int>(_Size)); for (int i = 0; i < _Size; i++) { for (int j = 0; j < _Size; j++) { unsigned long long int _Sum = 0; for (int k = 0; k < _Size; k++) // 모듈러 연산 _Sum += ((A[i][k] % MOD) * (B[k][j] % MOD)) % MOD; _Temp[i][j] = _Sum % MOD; } } return _Temp; } // 행렬을 제곱합니다. Matrix MatrixPow(Matrix& p_Matrix, unsigned long long int p_Cnt) { long long int _Size = p_Matrix.size(); Matrix _Res(_Size, vector<unsigned long long int>(_Size)); // 항등 행렬로 초기화 => _Res는 거듭제곱의 곱을 누적하는 데 사용 for (int i = 0; i < _Size; i++) _Res[i][i] = 1; while (p_Cnt > 0) { // 지수가 홀수인 경우 현재 _Res행렬과 입력 행렬을 곱하고 다시 할당 if (p_Cnt % 2 == 1) _Res = MatrixMultiply(_Res, p_Matrix); p_Matrix = MatrixMultiply(p_Matrix, p_Matrix); p_Cnt /= 2; // p_Matrix => A // cnt = 4 > A * A * A * A // cnt = 2 > (A * A) * (A * A) // cnt = 1 > ((A * A) * (A * A)) } return _Res; } int main() { cin >> _N >> _B; // 동적으로 행렬 생성 Matrix _Matrix(_N, vector<unsigned long long int>(_N)); for (int i = 0; i < _N; i++) { for (int j = 0; j < _N; j++) cin >> _Matrix[i][j]; } // 제곱 시작 Matrix C = MatrixPow(_Matrix, _B); for (int i = 0; i < _N; i++) { for (int j = 0; j < _N; j++) cout << C[i][j] << " "; cout << "\n"; } return 0; }
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 새로운 데이터 유형을 정의
typedef vector<vector<unsigned long long int>> Matrix;

long long int _N, _B;
constexpr int MOD = 1000;

// 행렬 제곱 계산
Matrix MatrixMultiply(Matrix& A, Matrix& B) {

    int _Size = A.size();

    Matrix _Temp(_Size, vector<unsigned long long int>(_Size));

    for (int i = 0; i < _Size; i++) {
        for (int j = 0; j < _Size; j++) {

            unsigned long long int _Sum = 0;

            for (int k = 0; k < _Size; k++) // 모듈러 연산
                _Sum += ((A[i][k] % MOD) * (B[k][j] % MOD)) % MOD;
            _Temp[i][j] = _Sum % MOD;
        }
    }
    return _Temp;
}

// 행렬을 제곱합니다.
Matrix MatrixPow(Matrix& p_Matrix, unsigned long long int p_Cnt) {

    long long int _Size = p_Matrix.size();

    Matrix _Res(_Size, vector<unsigned long long int>(_Size));

    // 항등 행렬로 초기화 => _Res는 거듭제곱의 곱을 누적하는 데 사용
    for (int i = 0; i < _Size; i++) 
        _Res[i][i] = 1;
    
    while (p_Cnt > 0) {

        // 지수가 홀수인 경우 현재 _Res행렬과 입력 행렬을 곱하고 다시 할당
        if (p_Cnt % 2 == 1) _Res = MatrixMultiply(_Res, p_Matrix);       
        p_Matrix = MatrixMultiply(p_Matrix, p_Matrix); 
        p_Cnt /= 2;
        // p_Matrix => A
        // cnt = 4 >  A * A * A * A
        // cnt = 2 > (A * A) * (A * A)
        // cnt = 1 > ((A * A) * (A * A))
    }
    return _Res;
}

int main()
{
    cin >> _N >> _B;

    // 동적으로 행렬 생성
    Matrix _Matrix(_N, vector<unsigned long long int>(_N));

    for (int i = 0; i < _N; i++) {
        for (int j = 0; j < _N; j++) 
            cin >> _Matrix[i][j];       
    }

    // 제곱 시작
    Matrix C = MatrixPow(_Matrix, _B);

    for (int i = 0; i < _N; i++) {
        for (int j = 0; j < _N; j++)
            cout << C[i][j] << " ";
        cout << "\n";
    }

    return 0;
}

수학은 너무 어려운 것 같다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다