알고리즘/배낭문제(DP)

BOJ 백준 5909 Bale Share

kyjdummy 2025. 4. 14. 20:15

 

문제 : https://www.acmicpc.net/problem/5909

 

[ 문제 요약 ]

  • 건초더미들과 그 무게들이 주어질 때, 건초더미들을 3개의 그룹으로 나누고, 3개의 건초 더미 중 최댓값이 최소가 되도록 한다.

 

[ 테스트 케이스 설명 ]

 

8	// 건초더미 개수 1<=20
14	// 건초더미 크기 1<=100
2
5
15
8
9
20
4
답 : 26

 

 

[ 문제 해설 ]

 

문제는 세 그룹으로 분할하는 문제지만, 세 그룹을 모두 고려하는 것은 상태가 너무 많아 효율적으로 풀기 어렵습니다.

 

대신, 두 그룹의 합에 대해 동적 계획법(DP)을 적용하여 만들 수 있는 가능한 합들을 기록하고,

 

나머지 세 번째 그룹은 전체 합에서 두 그룹의 합을 빼서 자동으로 결정되는 방식으로 접근합니다.

 

일반 배낭 문제에서는 가치의 최대화를 목표로 하지만,

 

이 문제에서는 세 그룹 중 가증 큰 합(즉, 불균형 정도)을 최소화하는 데 초점을 맞춥니다.

 

문제 해결을 위해 2차원 DP 배열을 사용하여

 

[ 첫 번째 그룹의 합계 i, 두 번째 그룹의 합계 j를 만드는 것이 가능한가? ]

 

를 기록합니다. 나머지 그룹은 전체 합에서 i와 j를 뺀 값(= group3)이 됩니다.

 

dp[i그룹합][j그룹합] = 가능한가?

 

코드를 보면 이해하기 쉽습니다.

 

[ 정답 코드 ]

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
class Main{
	public static void main(String[] args)throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N		= Integer.parseInt(br.readLine());	// 건초 더미 개수 1<=20
		int arr[]	= new int[N + 1];
		int sum		= 0;
		
		for(int i=1; i<=N; i++)
			sum += arr[i] = Integer.parseInt(br.readLine());	// 건초 더미 크기 1<=100
		// DP 배열: dp[i][j] = 일부 건초 더미를 그룹1과 그룹2로 나누어, 그룹1의 합이 i, 그룹2의 합이 j가 가능한지 여부
		boolean dp[][] = new boolean[sum + 1][sum + 1];
		
		dp[0][0] = true;// 아무것도 선택하지 않으면 그룹 합은 (0,0)
		// 건초더미 반복
		for(int now : arr)
		{
			for(int i=sum; i>=0; i--)				// 첫 번째 그룹, 중복 선택 방지를 위해 역순 탐색
			{
				for(int j=sum-i; j>=0; j--)			// 두 번째 그룹,	중복 선택 방지를 위해 역순 탐색
				{
					if(i>=now)
						dp[i][j] |= dp[i-now][j];	// i-now , j값이 참이면 i,j도 참임
					
					if(j>=now)
						dp[i][j] |= dp[i][j-now];	// i, j-now값이 참이면 i,j도 참임
				}
			}
		}
		
		int ans = sum + 1;
		
		for(int i=0; i<=sum / 2; i++)	// 그룹 1에 해당하는 값, 건초 그룹 3개중 두번째로 크다.
		{
			for(int j=0; j<=i; j++)		// 그룹 2에 해당하는 값, 건초 그룹 3개중 세번째로 크다.
			{
				int group3 = sum - i - j;// 그룹 3에 해당하는 값, 건초 그룹 3개중 가장 크다.
				// i와 j로 만들 수 있고, 그룹 3이 가장 클 때 결과 갱신
				if(dp[i][j] && group3>=i)
					ans = Math.min(ans, group3);
			}
		}
		
		System.out.print(ans);
	}
}

 

 

[ 코드 해설 ]

  • 건초 더미를 순회하며 dp에 값을 갱신하는 부분에서 i와 j 그룹을 역순으로 탐색하는 이유는, 한 건초 더미가 여러 번 사용되는 것을 막기 위함입니다.
  • 최종 해 도출 시, i 그룹과 j 그룹을 순회하며 sum에서 i, j 그룹을 빼서 group3을 만듭니다. 그리고 group3이 가능하면서, 그룹 중 가장 클 때(grou3≥ i) 값을 갱신하도록 합니다.

 

이 풀이의 핵심은 동적 계획법(DP)을 활용해 두 그룹의 가능한 합들을 전부 기록한 뒤, 전체 건초의 합에서 두 그룹의 합을 빼 그룹 3의 합을 유도해 내는 것입니다.

 

이 문제를 통해 동적 계획법이 단순한 최대/최소 문제뿐만 아니라, 여러 그룹으로 나눠 균형을 맞추는 다양한 문제에 적용될 수 있음을 이해할 수 있었습니다.