1 분 소요

파일 합치기 (백준 Gold 3)

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

연속된 파일을 합쳐서 하나의 파일을 만드는 데
필요한 최소 비용을 구하는 문제

  • 파일 1 : 40, 파일 2 : 30 이면
    합쳐진 파일 x = 40 + 30이다
    여기까지의 비용은 70

  • 이후 파일 x와 파일 3 : 30을 합치면
    파일 y = 70 + 30 = 100이지만
    여기까지의 총 비용은 170

이런식으로
모든 연속된 파일들을 합치면서
‘총 비용’을 적게 만드는 것이 목표

풀이 방식

일단, 이전 값을 활용할 수 있기에
dp문제라 생각하였다

또한 0~k 의 ‘특정 범위’에 해당하는 값을 이용하기에
2차원 dp라 생각

  • dp[0][k] : 0~k까지 합칠때 발생한 최소 비용

개인적으로 여기서 많이 삽질한 부분이 있었는데
바로 ‘파일 자체의 합’과 ‘합치는 비용’을 함께 계산하려 했던것

나는 dp[0][k] 에 0~k까지의 합도 포함했기에
dp[0][0] : 0번째 파일의 값
으로 설정하고 문제를 풀었다

그랬더니 개념의 혼동이 발생하여
파일끼리만 더한다던가, 이상한 배율을 적용한다던가 등의 오류를 범했다

다시 생각해보니
dp[0][0] 은 ‘파일 1개’ 그 자체이며
합치지 않았기에 dp[0][0] = 0 이 되어야 했다

동시에 파일들의 ‘합’자체를 관리하는 별도의 관리 공간이 필요하였다
그래서 sums라는 합용 2차원 배열을 이용하였다
(누적합을 사용하면 1차원 배열이 되었겠지만
삽질을 하느라 추가적인 응용을 스킵하였다)

이후 파일을 합칠때
dp[0][k]
min(dp[0][0] + sums[0][0] + dp[1][k] + sums[1][k],
dp[0][1] + sums[0][1] + dp[2][k] + sums[2][k] …)
방식으로 합쳐나가게 되었다

제출 코드

#include<iostream>
#include<vector>
#include<limits.h>

using namespace std;

typedef unsigned long long ull;

int main()
{
	int t;
	cin >> t;
	while (t > 0)
	{
		t--;
		int n;
		cin >> n;

		vector<vector<ull>> sums(n, vector<ull>(n, LONG_MAX)); // 각 범위의 합들
		vector<vector<ull>> dp(n, vector<ull>(n, LONG_MAX)); // 합쳐지는 비용

		for (int i = 0; i < n; i++)
		{
			cin >> sums[i][i];
			dp[i][i] = 0;
		}

		for (int i = 0; i < n - 1; i++)
		{
			sums[i][i + 1] = sums[i][i] + sums[i + 1][i + 1];
			dp[i][i + 1] = sums[i][i + 1];
		}

		for (int size = 2; size < n; size++)
		{
			for (int i = 0; i < n - size; i++)
			{
				ull minV = LONG_MAX;
				sums[i][i + size] = sums[i][i] + sums[i + 1][i + size];
				
				for (int j = 0; j < size; j++)
				{
					ull temp1 = dp[i][i + j] + sums[i][i+j];
					ull temp2 = dp[i + j + 1][i + size] + sums[i+j+1][i+size];

					minV = min(minV, temp1 + temp2);
				}
				
				// dp[0][3]
				dp[i][i + size] = minV;
			}
		}

		cout << dp[0][n - 1] << '\n';
	}

	return 0;
}

결과

Image

컴파일 오류는 unsigned 를 unsinged 로 잘못입력하여 발생한 오류이다

댓글남기기