알고리즘/문제 풀이

11066번: 파일 합치기

Themion 2022. 1. 4. 23:49

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

 

11066번: 파일 합치기

소설가인 김대전은 소설을 여러 장(chapter)으로 나누어 쓰는데, 각 장은 각각 다른 파일에 저장하곤 한다. 소설의 모든 장을 쓰고 나서는 각 장이 쓰여진 파일을 합쳐서 최종적으로 소설의 완성본

www.acmicpc.net

두 인접한 파일을 합칠 때 들어가는 총 비용은 두 파일을 각각 만들 때 들어가는 비용의 합과 두 파일을 합쳐 만들어진 파일의 크기를 더한 값과 같다. 이 때 이렇게 만들어진 파일의 크기는 해당 파일을 만들 때 사용한 모든 초기 파일의 크기의 합이다.

K개의 파일에서 모든 연속한 2개 ~ l - 1개의 파일을 최소의 비용으로 합치는 방법을 알고 있다고 하자. 모든 연속한 l개의 파일을 최소의 비용으로 합치기 위해선, 가능한 0 <= k <= l인 정수 k에 대해 k개의 파일과 l - k개의 파일을 먼저 합치는 비용과 만들어진 두 파일을 합치는 비용의 합을 최소화하는 k를 찾아 합쳐야 한다. 이 과정을 l이 K가 될 때까지 반복하면 정답을 얻을 수 있다.

#include <iostream>

using namespace std;

#define MAX_K 500
#define INF 0x3f3f3f3f

int min(int a, int b) { return a < b ? a : b; }

int test_case() {
    // K: 파일의 수, C[i][j]: i번 파일부터 j번 파일까지 합치는 최소 비용
    // sum[i]: 1번 파일부터 i번 파일까지의 용량의 합
    int K, C[MAX_K + 1][MAX_K + 1] = {{ 0, }}, sum[MAX_K + 1] = { 0, };

    // 문제의 조건을 입력받으며 sum을 갱신
    cin >> K;
    for (int i = 1; i <= K; i++) {
        cin >> C[i][i];
        sum[i] += sum[i - 1];
    }

    // 각 위치에서 파일을 하나씩 합치면서 최솟값을 계산
    for (int len = 1; len < K; len++) for (int i = 1; i + len <= K; i++) {
        // 아직 합치지 않은 파일의 비용을 INF로 설정
        C[i][i + len] = INF;

        // i와 i + len 사이의 모든 지점에 대해
        // 두 합친 파일 C[i][j]와 C[j][i + len]을 만드는 비용의 최솟값을 저장한 뒤
        for (int j = i; j < i + len; j++)
            C[i][i + len] = min(C[i][i + len], C[i][j] + C[j + 1][i + len]);

        // 두 파일을 합친 파일 C[i][i + len]을 만드는 비용을 더해 비용을 완성시킨다
        C[i][i + len] += sum[i + len] - sum[i - 1];
    }

    // 모든 파일을 합치는 비용의 최솟값을 반환
    // 이 때 원래 0이어야 할 각 C[i][i]를 i번째 파일의 크기로 설정했으므로
    // 오차를 바로잡기 위해 모든 파일의 크기의 합을 뺀 값을 반환한다
    return C[1][K] - sum[K];
}

int main() {
    // 입출력 속도 향상
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    int T;
    // 테스트 케이스의 수를 입력받고 각 테스트 케이스를 실행
    for (cin >> T; T--; ) cout << test_case() << '\n';
    return 0;
}

'알고리즘 > 문제 풀이' 카테고리의 다른 글

11286번: 절댓값 힙  (0) 2022.01.05
11279번: 최대 힙  (0) 2022.01.05
11057번: 오르막 수  (0) 2022.01.04
11055번: 가장 큰 증가 부분 수열  (0) 2022.01.04
11054번: 가장 긴 바이토닉 부분 수열  (0) 2022.01.04