티스토리 뷰
문제 출처 : https://www.acmicpc.net/problem/11066
문제 해결에 필요한 알고리즘 : DP ( Dynamic Programming )
해설
합쳐야 하는 파일을 두 수열로 나눌 수 있다. 최적으로 합쳐야 하는 구간을 i ~ j 라고 할 때 임의의 k에 대해 ( i <= k < j ) i ~ k 구간과 k + 1 ~ j 구간으로 나눌 수 있다. 이렇게 작은 부분문제로 나누어 문제를 해결 할 수 있다.
dp[i][j] = i ~ j 까지 최적으로 합친 값
ar[n] = n번째 파일의 크기
라고 할 때
라는 식이 성립한다.
이 때 이 식은 부분합을 이용해
만에 구할 수 있다.
시간 복잡도
테스트케이스의 수인 T의 제한은 문제에 나와있지 않으며 대략 1개의 케이스를 통과할 시간복잡도가 된다면 대회에서 문제를 해결 할 수 있었다.
이 코드는 find함수가 만큼 호출된다. 또 함수 내부의 반복문이
만큼 반복된다. 그래서 이 코드의 시간복잡도는
라는 시간복잡도를 갖게 된다.
시간복잡도는 느리다고 생각할 수 있지만, 모든 DP 테이블을 채우지 않고 함수 내부의 반복문도 길이가 짧아지기 때문에 실제론 더 나은 시간복잡도를 갖는다.
파일 합치기 코드 [ C ]
#include <string.h> #include <stdio.h> int ar[501], dp[501][501], mem[501]; int min(int i, int j) { return i < j ? i : j; } int find(int i, int j) { if (i == j) return 0; if (dp[i][j] != -1) return dp[i][j]; int k; dp[i][j] = 987654321; for (k = i; k < j; ++k) { dp[i][j] = min(dp[i][j], find(i, k) + find(k + 1, j)); } return dp[i][j] += mem[j] - (i > 0 ? mem[i - 1] : 0); } int main() { int t; scanf("%d", &t); for (; t--; ) { int i, j, n; memset(dp, -1, sizeof dp); scanf("%d", &n); for (i = 0; i < n; ++i) { scanf("%d", ar + i); mem[i] = ar[i] + (i > 0 ? mem[i - 1] : 0); } printf("%d\n", find(0, n - 1)); } return 0; }
'프로그래밍 > 알고리즘' 카테고리의 다른 글
[BOJ_3101_RN] 토끼의 이동 Problem Solving (0) | 2019.03.18 |
---|---|
[BOJ_2243_RN] 사탕상자 Problem Solving (0) | 2018.12.08 |
[BOJ_1715_RN] 카드 정렬하기 Problem Solving (0) | 2018.10.30 |
[BOJ_11652_RN] 카드 Problem Solving (1) | 2018.10.30 |
[BOJ_2156_RN] 포도주 시식 Problem Solving (0) | 2018.10.19 |
댓글