11066 파일 합치기
- 중요한 포인트는 2가지다.
- 연속한 파일만 합칠 수 있으며
-
파일은 2개의 연속된 파일을 합친 것이다.
- A1,A2,A3,A4,A5란 파일이 있다고 하자.
- 이 파일을 합치는 방법은 4가지가 있다.
- (A1),(A2,A3,A4,A5) : (1-1)/(2-5) = > (1-5)
- (A1,A2),(A3,A4,A5) : (1-2)/(3-5) => (1-5)
- (A1,A2,A3),(A4,A5) : (1-3)/(4-5) => (1-5)
-
(A1,A2,A3,A4)(A5) : (1-4)/(5-5) => (1-5)
- 이 네가지 방법 말고는 다섯가지 파일을 합치는 방법이 없다.
- 점화식을 구현할 때, 개수를 중요하게 여기지만. 개수보다 더 중요한게. file이 개수는 같지만, 구성되어 있는 파일이 다르므로 다른 경우로 잡아야 한다
-
따라서 파일의 시작 위치와 끝 위치를 알게 되면, 나타낼 수 있다.
- 1번부터 5번까지의 파일을 합친 것.
- D[i][j] = i번째부터 j번째 파일을 합치는 최소 비용으로 정의
- 예를 들어 첫번째는 D[1][1] + D[2][5] + 1~5 파일크기 (이게 파일을 합치는 비용이 된다)
일반화
- i번째부터 j번째 까지 파일이 있다.
- D[i][j]
- D[i][j]를 합치는 방법은 다음과 같이 나타낼 수 있다
- (Ai, Ai+1, … Ak)(Ak+1… Aj-1,Aj)
- Min(D[i][k] + D[k+1][j] + i번째부터 j번째까지 파일 크기의 합)을 더해주면 된다.
- 변수의 범위는 i<= k <= j-1
- 어떻게 for문을 돌아야 할지가 애매하다.
- 이 문제도 팰린드롬 문제와 크기가 문제의 크기를 나타낸다.
- 다이나믹 에서의 작은 문제를 정의하는 크기가 i~j까지 포함된 파일의 크기가 된다.
def go(i, j):
if i == j:
return 0
if d[i][j] != -1:
return d[i][j]
ans = d[i][j]
cost = sum(a[i:j+1])
for k in range(i, j):
temp = go(i,k) + go(k+1,j) + cost
if ans == -1 or ans > temp:
ans = temp
d[i][j] = ans
return ans
t = int(input())
for _ in range(t):
n = int(input())
a = list(map(int,input().split()))
d = [[-1]*n for _ in range(n)]
print(go(0,n-1))
- 문제의 시간제한 때문에 시간초과를 받을 수 밖에 없다.
#include <cstdio>
#include <cstring>
int a[501];
int d[501][501];
int go(int i, int j) {
if (i == j) {
return 0;
}
if (d[i][j] != -1) {
return d[i][j];
}
int &ans = d[i][j];
int sum = 0;
for (int k=i; k<=j; k++) {
sum += a[k];
}
for (int k=i; k<=j-1; k++) {
int temp = go(i, k) + go(k+1, j) + sum;
if (ans == -1 || ans > temp) {
ans = temp;
}
}
return ans;
}
int main() {
int t;
scanf("%d",&t);
while (t--) {
memset(d,-1,sizeof(d));
int n;
scanf("%d",&n);
for (int i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
printf("%d\n",go(1, n));
}
return 0;
}
import sys
def sol(N, data):
S = [0] * (500 + 1)
D = [[0 for j in range(500 + 1)] for i in range(500 + 1)]
K = [[0 for j in range(500 + 1)] for i in range(500 + 1)]
for i in range(1, N + 1):
S[i] = S[i - 1] + data[i - 1]
for i in range(1, N + 1):
D[i - 1][i] = 0
K[i - 1][i] = i
for d in range(2, N + 1):
for i in range(0, N - d + 1):
j = i + d
D[i][j] = 10 ** 9
for k in range(K[i][j - 1], K[i + 1][j] + 1):
v = D[i][k] + D[k][j] + S[j] - S[i]
if D[i][j] > v:
D[i][j] = v
K[i][j] = k
return D[0][N]
if __name__ == "__main__":
input = sys.stdin.readline
T = int(input())
for i in range(T):
N = int(input())
data = list(map(int, input().split()))
sys.stdout.write(str(sol(N, data)) + "\n")
참고자료 codeplus