Data Structure & Algorithms/Algorithms-Problems

백준 11066. 파일 합치기

여늘(yeonuel) 2023. 10. 3. 00:29

 

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

 

11066번: 파일 합치기

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

www.acmicpc.net

 

 

 

1. 문제 설명

 

소설의 모든 장을 쓰고 나서는 각 장이 쓰여진 파일을 합쳐서 최종적으로 소설의 완성본이 들어있는 한 개의 파일을 만든다. 

이 과정에서 두 개의 파일을 합쳐서 하나의 임시파일을 만들고, 이 임시파일이나 원래의 파일을 계속 두 개씩 합쳐서 소설의 여러 장들이 연속이 되도록 파일을 합쳐나가고, 최종적으로는 하나의 파일로 합친다.

 

두 개의 파일을 합칠 때 필요한 비용(시간 등)이 두 파일 크기의 합이라고 가정할 때, 최종적인 한 개의 파일을 완성하는데 필요한 비용의 총 합을 계산하시오.

 

2. 접근법

 

"이 임시파일이나 원래의 파일을 계속 두 개씩 합쳐서 소설의 여러 장들이 연속이 되도록 파일을 합쳐나가고, 최종적으로는 하나의 파일로 합친다." 부분을 통해 해당 문제는 그 하위 문제로 분할이 가능함을 알 수 있다

(이때, 연속이 되도록 파일을 합쳐나감이 중요함)

 

소설 완성본은 두 개의 파일이 합쳐져서 만들어진 것이고

그 두 개의 파일도 더 작은 파일들로 합쳐져서 만들어진 것이다

여기서 합쳐지는 과정에서 비용이 발생하고 소설 완성본을 만들 때 최소 비용을 구해야한다

 

즉, 소설 완성본을 구성하는 두 개의 파일을 분할하고 각각의 파일들 또한 두 개의 파일들로 분할하는 과정을 반복해서

최소 비용을 구해나감

 

일반화를 시켜보면 파일이 i부터 j까지 합쳐진 큰 파일이 있다고 가정했을 때

해당 파일은 k를 기준으로 i~k까지의 합쳐진 파일과 k+1~j까지 합쳐진 파일을 합친 결과라고 할 수 있다

이때, k에 따라서 i부터 j까지 합쳐진 큰 파일을 만드는 비용이 달라지므로 k는 변수로 다뤄서 i부터 j까지 합쳐진 파일을 만드는 최소 비용을 구해야한다

 

 

 

 

3. 설계

 

1. dp를 재귀적으로 호출하자(top-down)

- 파일의 합쳐진 범위를 i, j라고 가정

- i == j 일 때 0 반환 -> 하나의 파일

- dp 메모이제이션을 통해 중복 회피

-재귀 호출(dp 적용)

 

 

4. 코드

import java.util.*;
import java.io.*;



public class Main {

    static int[] a;
    static int[][] dp;

    static int go(int i, int j) {
        if (i == j) {
            return 0;
        }

        if (dp[i][j] != -1) {
            return dp[i][j];
        }

        int ans = -1;
        int sum = 0;
        for (int k=i; k<=j; k++) {
            sum += a[k];
        }

        for (int k=i; k<j; k++) {
            int tmp = go(i, k) + go(k+1, j) + sum;
            if (ans == -1 || ans > tmp) ans = tmp;
        }

        dp[i][j] = ans;
        return ans;
    }

    public static void main(String args[]) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int tc = Integer.parseInt(br.readLine());

        while (tc-- > 0) {
            int n = Integer.parseInt(br.readLine());
            String[] numberStr = br.readLine().split(" ");

            a = new int[n+1];
            dp = new int[n+1][n+1];

            for (int i=1; i<=n; i++) {
                a[i] = Integer.parseInt(numberStr[i-1]);
                Arrays.fill(dp[i], -1);
            }

            int ans = go(1, n);
            bw.write(ans + "\n");
        }

        bw.flush();
        bw.close();
    }
}