2017년 6월 3일 토요일

11049 행렬 곱셈 순서

백준 11049 행렬 곱셈 순서 https://www.acmicpc.net/problem/11049

<유사문제>
11066 파일 합치기 https://www.acmicpc.net/problem/11066

행렬은 곱셈에 대해 결합법칙이 성립한다. 따라서 값은 같지만 곱셈횟수는 결합법칙에 따라 바뀐다.

행렬 A(10*5), B(5*20), C(20*15)를 예로들면
(A(BC)) = 10*5*15 + (5*20*15) = 2250
((AB)C) = (10*5*20) + 10*20*15 = 4000 임을 알 수 있다.

주어진 문제에서는 최소 행렬 곱셈횟수를 구하는 문제이다.
이 문제는 dp로 풀 수 있다.

$DP[i][j]$ : 구간[i, j]에서 최소 행렬 곱셈 횟수

$DP[i][j] = min(DP[i][j], DP[i][k] + DP[k+1][j] + d_{i-1}*d_{k}*d_{j})$

$N번째 행렬 : A*B$ 이라면  $d_{N} = A, d_{N+1} = B $


#include <cstdio>
#define min(a,b) ((a)<(b))?(a):(b)
#define INF 987654321
int N;
int dp[502][502];
int d[502];
int main(){
    scanf("%d"&N);
    scanf("%d%d"&d[0],&d[1]);
    for (int n = 1; n < N - 1; n++)
        scanf("%d%d"&d[n], &d[n + 1]);
    scanf("%d%d"&d[N - 1], &d[N]);
    for (int dia = 0; dia < N; dia++){
        for (int n = 1; n <= N - dia; n++){
            int m = n + dia;
            if (n == m){
                dp[n][m] = 0;
                continue;
            }
            dp[n][m] = INF;
            for (int k = n; k < m; k++){
                dp[n][m] = min(dp[n][m], dp[n][k] + dp[k + 1][m] + d[n - 1* d[k] * d[m]);
            }
        }
    }
    printf("%d\n", dp[1][N]);
    return 0;
}
cs


11066 파일합치기 문제도 최소 행렬 곱셈문제와 비슷하다.
다만 점화식 뒤에 부분이 살짝 다르다.

$DP[i][j]$ : 구간[i, j]의 파일을 하나로 합친 최소비용

$sum[i][j]$ : 구간[i,j]에서 각각의 파일 비용 들의 합

$DP[i][j] = min(DP[i][j], DP[i][k] + DP[k+1][j] + sum[i][j]$


#include <cstdio>
#define min(a,b) ((a)<(b))?(a):(b)
#define INF 987654321
int main(){
    int T;
    scanf("%d"&T);
    while (T--){
        int K;
        int dp[501][501= { 0 };
        int sum[501= { 0 };
        int c[501];
        scanf("%d"&K);
        for (int k = 1; k <= K; k++){
            scanf("%d"&c[k]);
            sum[k] += sum[k - 1+ c[k];
        }
        for (int dia = 0; dia <= K; dia++){        //끝나는 지점
            for (int n = 1; n <= K; n++){
                int m = n + dia;
                if (n == m || m > K)
                    continue;
                dp[n][m] = INF;
                for (int k = n; k < m; k++)
                    dp[n][m] = min(dp[n][m], dp[n][k] + dp[k + 1][m] + sum[m] - sum[n - 1]);
            }
        }
        printf("%d\n", dp[1][K]);
    }
    return 0;
}
cs

댓글 없음:

댓글 쓰기