-
[백준] #11049 행렬 곱셈 순서 - (DP)Algorithm/알고리즘 백준 풀이 2020. 3. 2. 20:14
문제
https://www.acmicpc.net/problem/11049
11049번: 행렬 곱셈 순서
첫째 줄에 입력으로 주어진 행렬을 곱하는데 필요한 곱셈 연산의 최솟값을 출력한다. 정답은 231-1 보다 작거나 같은 자연수이다. 또한, 최악의 순서로 연산해도 연산 횟수가 231-1보다 작거나 같다.
www.acmicpc.net
목표
행렬 연산을 할때 곱셈순서에 따라 값은 변하지 않지만 필요한 곱셈연산의 수는 달라진다.
따라서 주어진 행렬들이있을때 최소 곱셈 연산횟수를 구하라
풀이
ㅈㄴ어려움..
재귀로 푸는방법과 반복문으로 푸는방법이 있다.
1. 재귀
일단 재귀는 top-down으로 푸는데
점화식은
for (int i=left; i<right; ++i) {
dp[left][right] = min(result, func(left, i) + func(i+!, right) + (arr[left].first * arr[i].second * arr[right].second) )
}
즉, left, right구간의 최소 연산횟수는 left와 right사이에 i라는 변수를 두어 (left~i)연산횟수 + (i+1~right)연산횟수 + 앞 두 연산의 결과인 행렬 두개의 연산횟수로 계산한후, i값에 따른 최소 연산횟수를 최종 dp[left][right]로 저장한다.
코드
#include <iostream> #include <vector> #include <cstring> using namespace std; const int MAX = 501; const int INF = 987654321; int N; pair<int, int> arr[MAX]; int dp[MAX][MAX]; int func(int left, int right) { if (left == right) return 0; int result = dp[left][right]; if (result != -1) return result; result = INF; for (int i=left; i<right; ++i) { result = min(result, func(left, i) + func(i+1, right) + arr[left].first*arr[i].second*arr[right].second); } return result; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cin >> N; for (int i=0; i<N; ++i) { cin >> arr[i].first >> arr[i].second; } memset(dp, -1, sizeof(dp)); cout << func(0, N-1); return 0; }
2. 반복
이해하는데 너무 힘들었고 아직도 이해했는지 잘 모름
일단 bottom-up으로 코딩
diff라는 변수로 1번 for루프를 돈다
diff는 우리가 구하고자하는 행렬들 사이의 간격을 말한다. 즉 diff=1이면 1칸 떨어진 행렬들의 곱셈연산횟수를말함
10개의 행렬이 주어진다면 최종적으로 구해야할 행렬의 간격이 9임
예를 들어 diff=9 라면 최종적으로 dp[1][10]을 구하는거임
따라서 diff=0이면 같은 행렬이므로 0번의 연산, diff=1이면 옆행렬과의 연산횟수, diff=5라면 5칸뒤의 행렬과의 연산 횟수를 말함
다음 start는 구할 행렬집합의 시작인덱스 end는 마지막인덱스 따라서 end = start + diff임
다음 mid는 구할 행렬집합의 연산횟수를 중간에 있는 행렬을 기준으로 나누는데 필요한 인덱스
코드
#include <iostream> #define MAX 501 using namespace std; int N; int arr[MAX][2]; int dp[MAX][MAX]; //diff = 연산횟수를 구할 행렬의 간격 //start = 구할 행렬집합의 시작점 //end = 구할 행렬집합의 끝점 //mid = 구할 행렬집합의 연산 순서를 바꾼 값들을 비교하기위한 변수 int func() { for (int diff = 1; diff < N; ++diff) { for (int start=1; start<=N-diff; ++start) { int end = start + diff; int res = 987654321; for (int mid = start; mid<end; ++mid) { int tmp = dp[start][mid] + dp[mid+1][end] + arr[start][0]*arr[mid][1]*arr[end][1]; if (res > tmp) res = tmp; } dp[start][end] = res; } } return dp[1][N]; } int main() { cin >> N; for (int i=1; i<=N; ++i) { cin >> arr[i][0] >> arr[i][1]; } cout << func(); }
'Algorithm > 알고리즘 백준 풀이' 카테고리의 다른 글
[백준] #11062 카드게임 - (DP) (0) 2020.03.11 [백준] #14003 가장 긴 증가하는 부분수열5 - (DP) (0) 2020.03.02 [백준] #19115 가장 큰 정사각형 - (DP) (0) 2020.03.02 [백준] #9252 LCS2(Longest Common Subsequence) - (DP) (0) 2020.03.02 [백준] #11659 구간합 구하기4 - (DP) (0) 2020.03.02