Algorithm/BOJ
[C++/ 백준 11066번] 파일 합치기 - DP(다이나믹 프로그래밍), prefixsum(누적합)
Rubi ❤️
2025. 6. 7. 18:33
728x90
반응형
📚 [C++/ 백준 11066번] 파일 합치기 - DP(다이나믹 프로그래밍), prefixsum(누적합)
🔍 문제 요약
- 문제링크 : 백준 11066번
- 주요 태그: DP 다이나믹프로그래밍, prefixsum 누적합
소설을 여러 장으로 나누어 작성하며, 각 장은 서로 다른 파일로 저장된다. 이 파일들을 하나로 합치기 위해 두 개씩 계속 합치기를 반복한다.
이때 두 파일을 합치는 데 드는 비용은 두 파일의 크기의 합이다.
파일의 순서를 바꿀 수는 없으며, 모든 파일을 하나로 합치기 위한 최소 비용을 구해보자.
💡 문제 분석
- 입력:
- 테스트케이스 수 T
- 각 테스트케이스마다 K (파일 개수), 그리고 각 파일의 크기 (정수 K개)
- 출력:
- 각 테스트케이스마다 모든 파일을 하나로 합치기 위한 최소 비용
- 제한 조건:
- 3 ≤ K ≤ 500
- 파일 크기 ≤ 10,000
- 파일 순서 변경 불가
🔑 아이디어
- 순서가 고정된 채로 최소 비용을 구하기
- 다이나믹 프로그래밍(DP) 방식 중 구간 DP(Interval DP) 를 사용
- dp[i][j]: i번째부터 j번째 파일까지 하나로 합치는 최소 비용
- 모든 가능한 분할점 k에 대해, 구간 [i~k], [k+1~j]를 각각 합친 비용 + 이 둘을 합치는 비용을 계산한다.
🧩 풀이 전략
✅ DP 테이블 정의
dp[i][j] = i부터 j까지의 파일을 하나로 합치기 위한 최소 비용
✅ 누적합(prefixSum) 정의
파일 합치는 데 필요한 비용은 해당 구간의 총합
누적합을 이용해 구간합을 O(1)로 계산할 수 있다.
prefixSum[i] = board[1] + board[2] + ... + board[i]
sum(i~j) = prefixSum[j] - prefixSum[i-1]
✅ 점화식
for (int k = i; k < j; k++) {
dp[i][j] = min(dp[i][j],
dp[i][k] + dp[k + 1][j] + sum(i~j));
}
- [i, j]를 k를 기준으로 나누고
- 왼쪽 파일 묶음 + 오른쪽 파일 묶음 + 두 묶음을 합치는 비용(전체 크기 합)
📦 예제 입력 & 출력
입력
2
4
40 30 30 50
15
1 21 3 4 5 35 5 4 3 5 98 21 14 17 32
출력
300
864
🖥️ 코드 (C++)
#include <iostream>
#include <climits>
using namespace std;
int board[501];
int prefixSum[501];
int dp[501][501];
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
fill(board , board + n + 1, 0);
fill(prefixSum , prefixSum + n + 1, 0);
for (int i = 0; i <= n; i++) {
fill(dp[i] , dp[i] + n+1, 0);
}
for (int i = 1; i <= n; i++) {
cin >> board[i];
prefixSum[i] = prefixSum[i - 1] + board[i];
}
//누적합 중 가장 큰 것 고르기 - 길이 2인 것 부터 시작해 늘려서 찾기
//첫 번째 합 + 첫 번째 합 + 두 번째 값 = 두 번째 값 + 두 번째 값합 + 현재 값 ..
//구간 DP
for (int len = 2; len <= n; len++) {
for (int i = 1; i <= n - len + 1; i++) {
int j = i + len - 1;
dp[i][j] = INT_MAX;
for(int k = i; k < j; k++) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]
+ prefixSum[j] - prefixSum[i- 1]);
}
}
}
cout << dp[1][n] << "\n";
}
return 0;
}
✅ 검증 및 테스트
🔍 예제 1: [40, 30, 30, 50]
가능한 병합 방식 중,
- (40+30) = 70, (30+50) = 80 → 최종 (70+80) = 150
- 총 비용: 70 + 80 + 150 = 300
🔍 예제 2: [1, 21, 3, 4, 5, 35, 5, 4, 3, 5, 98, 21, 14, 17, 32]
구간이 많아 직접 계산은 어렵지만, DP 테이블에 의해 최적 병합 경로를 찾아
최소 비용 = 864로 출력됩니다.
⏱️ 시간 복잡도
- 시간:
삼중 루프 → O(N³) = 500³ = 1.25억 → 충분히 해결 가능 - 공간:
dp[501][501], prefixSum[501], board[501] → O(N²)
✨ 결론
항목 | 내용 |
문제 유형 | 구간 DP |
사용 기법 | prefixSum, 삼중 반복문, 최적 분할점 탐색 |
핵심 포인트 | 누적합을 활용한 구간 합 계산, 모든 분할점 시도 |
추천 학습자 | 중급 이상 DP 연습자, 최적화 알고리즘 연습자 |
이 문제는 구간 DP의 전형적인 구조와 누적합 기법을 모두 익힐 수 있었다.
특히 dp[i][j] = min(dp[i][k] + dp[k+1][j] + 합) 패턴은 자주 보이는 유형이라고 하니 숙지해두면 좋을 것 같다.
728x90
반응형