ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 11049(행렬 곱셈 순서)
    전공/알고리즘 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문제는 특정한 알고리즘 방법이 아니다. 그냥 방법론? 이라고 해야할 것 같다. 

     

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

     

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

    '전공 > 알고리즘' 카테고리의 다른 글

    백준 1937(욕심쟁이 판다)  (0) 2020.07.17
    백준 2213(트리의 독립집합)  (0) 2020.07.16
    백준 11780(플로이드 2)  (0) 2020.07.10
    백준 1865(웜홀)  (0) 2020.07.10
    백준 1738(골목길) 벨만포드  (0) 2020.07.09

    댓글

Designed by Tistory.