백준 11049 행렬의 곱셈 순서 [c++]
in Develop / Solving
c++
문제 분석
- n개의 행렬이 주어진다.
- m * n, n * k의 행렬을 곱하면, m * n * k번의 연산을 하게 된다.
- n개의 행렬을 곱하는 데에, 가장 적게 연산하고 싶은데, 이 때의 연산수는 얼마인가.
입력조건
행렬의 갯수 n
n줄에 걸쳐서 {
각 행렬의 r c
}
풀이과정
- 문제를 보고 굉장히 막막하여서, 알고리즘 보기를 눌러보았고, 다이나믹 프로그래밍이 적혀 있는 걸 보고 큰 힌트를 얻었다.
- n * n 크기의 보드를 만들어서, 각 행렬을 곱해갈 때의 최소 연산 수를 구한다.
- 이게 모든 경우의 수를 고려할 수 있냐고 생각할 수 있지만, 놀랍게도 고려할 수 있다.
보드는 i * i 대각선을 기준으로, 위쪽의 반만 사용한다.
- 우선, i,i 위치에 행렬값들을 입력받는다.
- dp순회를 해야 하는데, c번째 행의 c-1 ~ 0순서로 역으로 dp를 진행한다.
- (r, c)위치를 채울 수 있는 경우의 수는 (r, r) * (r+1, c) ~ (r, c) * (r+c-1, c) 의 c-r개이다.
- 이들을 고려하며 dp를 채워가면, (0, n-1)위치에 원하는 값을 얻게 된다.


전체 코드
#include <iostream>
#include <limits>
#define INF numeric_limits<int>::max()
using namespace std;
struct matrix {
int r;
int c;
int sum = 0;
};
int main() {
int n;
cin >> n;
matrix map[n][n];
for(int i = 0; i < n; i++)
cin >> map[i][i].r >> map[i][i].c;
// 입력 완료.
for(int c = 0; c < n; c++) {
for(int r = c-1; r >= 0; r--) {
//map[r][c] 위치를 만들어야 함.
for(int d = r; d < c; d++) {
// map[r][d] 에서 r 가져옴;
// map[r+d][c] 에서 c 가져옴;
int tmpsum = map[r][d].sum + map[d+1][c].sum + (map[r][d].r * map[r][d].c * map[d+1][c].c);
if(map[r][c].sum == 0) {
map[r][c].sum = tmpsum;
map[r][c].r = map[r][r].r;
map[r][c].c = map[c][c].c;
}
else if(tmpsum < map[r][c].sum) {
map[r][c].sum = tmpsum;
map[r][c].r = map[r][d].r;
map[r][c].c = map[d+1][c].c;
}
}
}
}
cout << map[0][n-1].sum;
}