행렬은 알고리즘 문제를 풀 때도 그렇고, 3D 코딩을 할때도 필요하고 여러모로 쓸 경우가 많은것 같아 여기 정리합니다.


먼저 나이브한 행렬곱셈을 구현해보면 다음과 같습니다. (관련 문제: 백준 2740번 행렬곱셈)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
ll A[101][101], B[101][101], C[101][101];
 
int main(void)
{
    int n, m; scanf("%d %d"&n, &m);
    for (int y = 0; y < n; y++)
    for (int x = 0; x < m; x++
        scanf("%lld"&A[y][x]);
 
    int k; scanf("%d %d"&m, &k);
    for (int y = 0; y < m; y++)
    for (int x = 0; x < k; x++
        scanf("%lld"&B[y][x]);
 
    for (int y = 0; y < n; y++) {
        for (int x = 0; x < k; x++) {
            for (int i = 0; i < m; i++
                C[y][x] += A[y][i] * B[i][x];
            
            printf("%lld ", C[y][x]);
        }
        printf("\n");
    }
 
    return 0;
}
cs


특별할건 없고, 2차원 배열로 잡고 y, x (또는 행, 열 이라고도 표현 가능) 순으로 인덱스 할당해서 계산한다는 것..


근데 한가지 불편한점이 발견되는것은 곱셈결과를 리턴하도록 함수로 뺄 경우에 행렬을 리턴값으로 두기 까다롭다는 것이다 (2차원 배열이니까.. 한가지 work around는 걍 out-value 파라미터를 사용하는것.. 하지만 그렇더라도 리턴값처럼 복사기반이 아니기 때문에 값의 정합성(오버라이팅 된다거나..)에 대해 항상 고민해야한다.) 

따라서 자연스럽게 2차원배열 그 자체로 쓰는것보다 struct나 class로 빼는걸 생각하게 되는데.. 대입연산자나 생성자, 소멸자, 멤버함수등 생각할게 많아지고 코드의 단순함이 많이 훼손(?)된다.


vector의 vector를 사용하면 위의 리턴문제를 비교적 간단하게 해결할 수 있다. 아래 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <bits/stdc++.h>
using namespace std;
 
typedef vector<vector<int>> matrix;
 
matrix mul(matrix A, matrix B)
{
    int n = A.size(), m = A[0].size(), k = B[0].size();
    matrix C(n, vector<int>(k));
 
    for (int y = 0; y < n; y++)
    for (int x = 0; x < k; x++)
    for (int i = 0; i < m; i++)
        C[y][x] += A[y][i] * B[i][x];
    return C;
}
 
int main(void)
{
    int n, m; scanf("%d %d"&n, &m);
    matrix A(n, vector<int>(m));
    for (int y = 0; y < n; y++)
    for (int x = 0; x < m; x++
        scanf("%d"&A[y][x]);
 
    int k; scanf("%d %d"&m, &k);
    matrix B(m, vector<int>(k));
    for (int y = 0; y < m; y++)
    for (int x = 0; x < k; x++
        scanf("%d"&B[y][x]);
 
    matrix C(n, vector<int>(k));
    C = mul(A, B);
    for (int y = 0; y < n; y++) {
        for (int x = 0; x < k; x++) {
            printf("%d ", C[y][x]);
        }
        printf("\n");
    }
 
    return 0;
}
cs



연산자 오버로딩을 사용하면 mul 함수대신 * 기호를 사용할수도 있다. 다음을 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <bits/stdc++.h>
using namespace std;
 
typedef vector<vector<int>> matrix;
 
matrix operator * (matrix A, matrix B) 
{
    int n = A.size(), m = A[0].size(), k = B[0].size();
    matrix C(n, vector<int>(k));
 
    for (int y = 0; y < n; y++)
    for (int x = 0; x < k; x++)
    for (int i = 0; i < m; i++)
        C[y][x] += A[y][i] * B[i][x];
    return C;
}
 
int main(void)
{
    int n, m; scanf("%d %d"&n, &m);
    matrix A(n, vector<int>(m));
    for (int y = 0; y < n; y++)
    for (int x = 0; x < m; x++
        scanf("%d"&A[y][x]);
 
    int k; scanf("%d %d"&m, &k);
    matrix B(m, vector<int>(k));
    for (int y = 0; y < m; y++)
    for (int x = 0; x < k; x++
        scanf("%d"&B[y][x]);
 
    matrix C(n, vector<int>(k));
    C = A * B;
    for (int y = 0; y < n; y++) {
        for (int x = 0; x < k; x++) {
            printf("%d ", C[y][x]);
        }
        printf("\n");
    }
 
    return 0;
}
cs


반응형

'Programming > Problem Solving' 카테고리의 다른 글

C++ bigint class  (0) 2020.03.30
백준 9663번 N-Queen  (0) 2020.03.15
C언어에서 표준입력으로 string 입력 받기  (0) 2020.02.21
백준 팁모음  (0) 2019.03.18
백준 제출시 오류유형 정리  (0) 2019.03.18

+ Recent posts