전공/알고리즘

백준 11049(행렬 곱셈 순서)

xkdlaldfjtnl 2020. 7. 15. 14:56

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

 

11049번: 행렬 곱셈 순서

첫째 줄에 입력으로 주어진 행렬을 곱하는데 필요한 곱셈 연산의 최솟값을 출력한다. 정답은 231-1 보다 작거나 같은 자연수이다. 또한, 최악의 순서로 연산해도 연산 횟수가 231-1보다 작거나 같�

www.acmicpc.net

 

오랜만의 알고리즘

 

컨디션이 너무 안좋아져서..

 

아무튼 이 문제를 보면 대충 감이 안온다. 어떻게든 풀 수는 있을것 같은데..

처음에는 행값이 큰 거 순서대로 연산횟수를 줄이면 어떨까 싶었지만, 진행방법이 떠오르지 않아서 스킵하고, 스터디에서 진행하는 dp식으로 문제를 접근하였다. 

 

 

dp를 적용시키려면 문제의 부분 뭉텅이도 전체처럼 풀수 있을때 적용시키는 것 같다. 

 

뭔가 부분문제도 전체 문제처럼 반복된다고 생각이 든다면 정확할 필요없이, 그냥 대략적인 방법을 좀 더 구체화 해보자. 

 

이 문제도 처음에는 정교할 필요가 없다. 

 

ABCDE를 계산하는 방법을 생각해보면 된다. 

 

(AB)(CDE)이런식으로 전체 문제를 계산 가능하다. 

 

여기서 A(BCDE)

 

(BCDE)를 다시 전체 문제로 생각해서 계속해서 반복 계산하면 원하는 결과를 얻을 수 있을 것이라고 생각하기 쉽지 않을까 생각한다. 

 

그러면 이제 필요한건 점화식(코드)구현 

 

dp[i][j] := i,j까지 최소 연산 값을 저장하고 

 

dp[i][j] = min(dp[i][i+k] + dp[i+k+1][j] + a*b*c)를 k의 값으로 반복해서 그 중 가장 작은 dp[i][j]를 구한다. 

 

k가 의미하는건 

 

ABCDE에서 

 

어디를 가를것인가를 의미한다. 

 

k=1이면 (AB)(CDE)이런식으로 

 

 

여기서 for문을 돌릴때 주의할 점이 있다. 

 

단순 for(int i = ~){

         for(int j = i ~ ) 

 

로 돌리게 된다면 

 

dp[1][4]을 구하려고할때

 

위의 코드에서 비교해야 하는 dp[1][2] 는 구해져 있지만 dp[3][4]의 값은 구해져 있지 않은 상태기 때문에, 원하는 결과를 얻어 낼 수 없다. 따라서 길이가 1인 경우 2인경우 3인경우 순서대로 구한다. 

 

나머지 값들은 잘 설정해주면 된다.

#include<iostream>
#include<vector>
using namespace std;
#define MAX 501

vector<pair<int, int> > mat(MAX);
int dp[MAX][MAX];
int r, c, N;
int min_n = 987654321;


int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;
	for (int i = 1; i <= N; i++) {
		cin >> r >> c;
		mat[i].first = r;
		mat[i].second = c;
	}
	for (int l = 1; l < N; l++) {
		for (int i = 1; i <= N-l; i++) {
			min_n = 987654321;
			int j = l + i;
			for (int k = 0; k < l; k++) {
				int temp = dp[i][i + k] + dp[i + k + 1][j] + mat[i].first*mat[i+k].second*mat[j].second;
				if (min_n > temp) {
					min_n = temp;
				}
			}
			dp[i][j] = min_n;
		}
	}
	cout << dp[1][N] << "\n";
}

 

 

dp문제는 특정한 알고리즘 방법이 아니다. 그냥 방법론? 이라고 해야할 것 같다. 

 

작은 문제의 해결방법과 큰 문제의 해결방법이 같다고 생각이 들면 그냥 대략적인 방법을 생각해보자 꼭 확실할 필요는 없는 것 같다. 

 

어차피 구체적으로 생각하기 시작하면서 문제되는 경우를 거르기 쉬우니깐