티스토리 뷰
참고: https://www.acmicpc.net/problem/11066
11066번: 파일 합치기
소설가인 김대전은 소설을 여러 장(chapter)으로 나누어 쓰는데, 각 장은 각각 다른 파일에 저장하곤 한다. 소설의 모든 장을 쓰고 나서는 각 장이 쓰여진 파일을 합쳐서 최종적으로 소설의 완성본
www.acmicpc.net
DP로 해결해야 하는 문제이기 때문에 점화식을 세우는 것이 중요합니다. 점화식은 아래와 같습니다
DP[i][j]: files[i]에서 files[j]까지 합치는 총 비용
1 2 3 4 의 파일들이 존재할 때 files[0]에서 files[3]까지 파일을 합치는 방법은 여러가지가 있습니다.
(1 + 2) + (3 + 4)
1 + ((2 + 3) + 4)
(1 + (2 + 3)) + 4
....
따라서 시작 지점과 끝 지점의 파일을 모두 더할 때 중간 계산 중 최소 값을 구해야 합니다. 이를 수도 코드로 나타내면 아래와 같습니다.
for j <- start to end-1:
dp[start][end] =
MIN(dp[start][end], dp[start][j] + dp[j+1][end] + (arr[start] + ... + arr[end]))
dp[start][j] + dp[j+1][end]
위 식은 files[start] ~ files[j]까지와 files[j+1] ~ files[end]까지 비용의 합을 의미합니다.
arr[start] + ... + arr[end]
위 식은 file[start] ~ file[end] 까지 합을 의미합니다. 누적 합 알고리즘을 사용하면 쉽게 나타낼 수 있습니다.
예를들어, (1 + 2) + (3 + 4)의 경우 dp[0][1] = 3, dp[2][3] = 7이 됩니다. 그리고 file[0] ~ file[3]의 합은 10입니다.
따라서 위 방식의 최종 비용은 3 + 7 + 10 = 20이 됩니다.
이렇게 구한 비용들을 모두 비교하여 최소값을 구하면 문제를 해결할 수 있습니다.
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.util.StringTokenizer; | |
public class BOJ11066 { | |
private static BufferedReader br; | |
public static void main(String[] args) throws NumberFormatException, IOException { | |
br = new BufferedReader(new InputStreamReader(System.in)); | |
int T = Integer.parseInt(br.readLine()); | |
for (int i=0;i<T;i++) { | |
System.out.println(mergeFiles()); | |
} | |
} | |
public static int mergeFiles() throws NumberFormatException, IOException { | |
int N = Integer.parseInt(br.readLine()); | |
int[] files = getFiles(N); | |
int[] acc = accumulate(files); | |
int[][] dp = new int[N][N]; | |
for (int step=1;step<N;step++) { | |
for(int start=0;start<N-step;start++) { | |
int end = start + step; | |
dp[start][end] = Integer.MAX_VALUE; | |
for (int j=start;j<end;j++) { | |
dp[start][end] = Math.min( | |
dp[start][end], | |
dp[start][j] + dp[j+1][end] + acc[end+1] - acc[start]); | |
} | |
} | |
} | |
return dp[0][N-1]; | |
} | |
public static int[] accumulate(int[] arr) { | |
int[] res = new int[arr.length+1]; | |
for (int i=0;i<arr.length;i++) { | |
res[i+1] = res[i] + arr[i]; | |
} | |
return res; | |
} | |
public static int[] getFiles(int N) throws IOException { | |
int[] files = new int[N]; | |
StringTokenizer st = new StringTokenizer(br.readLine(), " "); | |
for (int i=0;i<N;i++) { | |
files[i] = Integer.parseInt(st.nextToken()); | |
} | |
return files; | |
} | |
} |
from sys import stdin | |
from collections import defaultdict | |
readline = stdin.readline | |
T = int(readline()) | |
def solve(): | |
for _ in range(T): | |
print(merge_files()) | |
def merge_files(): | |
N = int(readline()) | |
files = list(map(int, readline().split())) | |
acc = accumulate(files) | |
dp = [[0 for _ in range(N)] for _ in range(N)] | |
for step in range(1, N): | |
for start in range(N-step): | |
end = start + step | |
dp[start][end] = float('inf') | |
for j in range(start, end): | |
dp[start][end] = min( | |
dp[start][end], | |
dp[start][j] + dp[j+1][end] + acc[end] - acc[start-1]) | |
return dp[0][N-1] | |
def accumulate(arr): | |
res = defaultdict(int) | |
for i in range(len(arr)): | |
res[i] = res[i-1] + arr[i] | |
return res | |
solve() |
'PS > 백준' 카테고리의 다른 글
[백준] 20167, 20181 꿈틀 꿈틀 호석 애벌레 (0) | 2021.10.06 |
---|---|
[백준] 20166 문자열 지옥에 빠진 호석 (0) | 2021.08.29 |
[백준] 2133 타일 채우기 - 파이썬 (0) | 2021.07.06 |
[백준] 2631 줄세우기 (0) | 2021.06.18 |
[백준] 5557 1학년 (0) | 2021.06.17 |